霍夫(Hough)直线变换(直线检测)
0 原理
霍夫变换在检测各种形状的的技术中非常流行,如果你要检测的形状可以用数学表达式写出,你就可以是使用霍夫变换检测它。及时要检测的形状存在一点破坏或者扭曲也可以使用。我们下面就看看如何使用霍夫变换检测直线。
首先将一条直线用一个点表示,这样用一个点表示直线上所有的点,一开始人们使用斜截式y=kx+q中的(k,q)来表示一条直线。
首先将一条直线用一个点表示,这样用一个点表示直线上所有的点,一开始人们使用斜截式y=kx+q中的(k,q)来表示一条直线。

变换后的空间成为霍夫空间。即:笛卡尔坐标系中一条直线,对应霍夫空间的一个点。
反过来同样成立(霍夫空间的一条直线,对应笛卡尔坐标系的一个点):

再来看看A、B两个点,对应霍夫空间的情形:

一步步来,再看一下三个点共线的情况:

可以看出如果笛卡尔坐标系的点共线,这些点在霍夫空间对应的直线交于一点:这也是必然,共线只有一种取值可能。
如果不止一条直线呢?再看看多个点的情况(有两条直线):

其实(3,2)与(4,1)也可以组成直线,只不过它有两个点确定,而图中A、B两点是由三条直线汇成,这也是霍夫变换的后处理的基本方式:选择由尽可能多直线汇成的点。
看看,霍夫空间:选择由三条交汇直线确定的点(中间图),对应的笛卡尔坐标系的直线(右图)。

到这里问题似乎解决了,已经完成了霍夫变换的求解,但是如果像下图这种情况呢?
但这样做会有一个弊端,那就是当直线趋近于垂直时,斜率a会趋近于无穷大。这一困难的解决方法之一就是使用法线来表示直线。

在极坐标系下,其实是一样的:极坐标的点→霍夫空间的正弦线,这条正弦线上的所有点都过极坐标中的那个点。


简单来说就是每个点在霍夫空间的弦线与其他点的弦线交一次,就会在累加器的ρθ平面中累加一次。下面的动画很好的演示了这个过程

1 OpenCV中的霍夫变换
上面介绍的整个过程在OpenCV中都被封装进了一个函数:cv2.HoughLines()。返回值就是极坐标表示的直线(ρ, θ)。ρ 的单位是像素,θ 的单位是弧度。
cv2.HoughLines(image, rho, theta, threshold, lines, sen, stn, min_theta, max_theta)
- image:输入图像,8-bit灰度图像
- rho:生成极坐标时候的像素扫描步长
- theta:生成极坐标时候的角度步长
- threshold:阈值,只有获得足够交点的极坐标点才被看成是直线
- lines:返回值,极坐标表示的直线(ρ, θ)
- sen:是否应用多尺度的霍夫变换,如果不是设置0表示经典霍夫变换
- stn:是否应用多尺度的霍夫变换,如果不是设置0表示经典霍夫变换
- min_theta:表示角度扫描范围最小值
- max_theta:表示角度扫描范围最大值
这种方法仅仅是一条直线都需要两个参数,这需要大量的计算。Probabilistic_Hough_Transform 是对霍夫变换的一种优化。它 不会对每一个点都进行计算,而是从一幅图像中随机选取(是不是也可以使用 图像金字塔呢?)一个点集进行计算,对于直线检测来说这已经足够了。但是 使用这种变换我们必须要降低阈值(总的点数都少了,阈值肯定也要小呀!)。
函数如下:
cv2.HoughLinesP(image, rho, theta, threshold, lines, minLineLength, maxLineGap)
- src:输入图像,必须8-bit的灰度图像
- rho:生成极坐标时候的像素扫描步长
- theta:生成极坐标时候的角度步长
- threshold:阈值,只有获得足够交点的极坐标点才被看成是直线
- lines:输出的极坐标来表示直线
- minLineLength:最小直线长度,比这个短的线都会被忽略。
- maxLineGap:最大间隔,如果小于此值,这两条直线 就被看成是一条直线。
举个例子:
import cv2
import numpy as np img = cv2.imread('test19.jpg')
img1 = img.copy()
img2 = img.copy()
img = cv2.GaussianBlur(img, (3, 3), 0)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 50, 150, apertureSize=3)
lines = cv2.HoughLines(edges, 1, np.pi/180, 110) for line in lines:
rho = line[0][0]
theta = line[0][1]
a = np.cos(theta)
b = np.sin(theta)
x0 = a*rho
y0 = b*rho
x1 = int(x0 + 1000*(-b))
y1 = int(y0 + 1000*(a))
x2 = int(x0 - 1000*(-b))
y2 = int(y0 - 1000*(a)) cv2.line(img1, (x1, y1), (x2, y2), (0, 0, 255), 2) lines = cv2.HoughLinesP(edges, 1, np.pi/180, 30, 300, 5) for line in lines:
x1 = line[0][0]
y1 = line[0][1]
x2 = line[0][2]
y2 = line[0][3]
cv2.line(img2, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.imshow('houghlines3', img1)
cv2.imshow('edges', img2)
cv2.waitKey(0)
print(lines)
结果如下:

带有滑动条,用于调节HoughLines的参数
import cv2
import numpy as np
from matplotlib import pyplot as plt def nothing(x): # 滑动条的回调函数
pass src = cv2.imread('test19.jpg')
srcBlur = cv2.GaussianBlur(src, (3, 3), 0)
gray = cv2.cvtColor(srcBlur, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 50, 150, apertureSize=3)
WindowName = 'Approx' # 窗口名
cv2.namedWindow(WindowName, cv2.WINDOW_AUTOSIZE) # 建立空窗口 cv2.createTrackbar('threshold', WindowName, 0, 60, nothing) # 创建滑动条 while(1):
img = src.copy()
threshold = 100 + 2 * cv2.getTrackbarPos('threshold', WindowName) # 获取滑动条值 lines = cv2.HoughLines(edges, 1, np.pi/180, threshold) for line in lines:
rho = line[0][0]
theta = line[0][1]
a = np.cos(theta)
b = np.sin(theta)
x0 = a*rho
y0 = b*rho
x1 = int(x0 + 1000*(-b))
y1 = int(y0 + 1000*(a))
x2 = int(x0 - 1000*(-b))
y2 = int(y0 - 1000*(a)) cv2.line(img, (x1, y1), (x2, y2), (0, 0, 255), 2) cv2.imshow(WindowName, img)
k = cv2.waitKey(1) & 0xFF
if k == 27:
break
cv2.destroyAllWindows()
结果如下:


带有滑动条,用于调节HoughLinesP的参数
import cv2
import numpy as np
from matplotlib import pyplot as plt def nothing(x): # 滑动条的回调函数
pass src = cv2.imread('test19.jpg')
srcBlur = cv2.GaussianBlur(src, (3, 3), 0)
gray = cv2.cvtColor(srcBlur, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 50, 150, apertureSize=3)
WindowName = 'Approx' # 窗口名
cv2.namedWindow(WindowName, cv2.WINDOW_AUTOSIZE) # 建立空窗口 cv2.createTrackbar('threshold', WindowName, 0, 100, nothing) # 创建滑动条
cv2.createTrackbar('minLineLength', WindowName, 0, 100, nothing) # 创建滑动条
cv2.createTrackbar('maxLineGap', WindowName, 0, 100, nothing) # 创建滑动条 while(1):
img = src.copy()
threshold = cv2.getTrackbarPos('threshold', WindowName) # 获取滑动条值
minLineLength = 2 * cv2.getTrackbarPos('minLineLength', WindowName) # 获取滑动条值
maxLineGap = cv2.getTrackbarPos('maxLineGap', WindowName) # 获取滑动条值 lines = cv2.HoughLinesP(edges, 1, np.pi/180, threshold, minLineLength, maxLineGap) for line in lines:
x1 = line[0][0]
y1 = line[0][1]
x2 = line[0][2]
y2 = line[0][3]
cv2.line(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.imshow(WindowName, img)
k = cv2.waitKey(1) & 0xFF
if k == 27:
break
cv2.destroyAllWindows()
结果如下:


霍夫(Hough)直线变换(直线检测)的更多相关文章
- opencv —— HoughCircles 霍夫圆变换原理及圆检测
霍夫圆变换原理 霍夫圆变换的基本原理与霍夫线变换(https://www.cnblogs.com/bjxqmy/p/12331656.html)大体类似. 对直线来说,一条直线能由极径极角(r,θ)表 ...
- OpenCV 学习笔记03 直线和圆检测
检测边缘和轮廓不仅重要,还经常用到,它们也是构成其他复杂操作的基础. 直线和形状检测与边缘和轮廓检测有密切的关系. 霍夫hough 变换是直线和形状检测背后的理论基础.霍夫变化是基于极坐标和向量开展的 ...
- opencv —— HoughLines、HoughLinesP 霍夫线变换原理(标准霍夫线变换、多尺度霍夫线变换、累积概率霍夫线变换)及直线检测
霍夫线变换的原理 一条直线在图像二维空间可由两个变量表示,有以下两种情况: ① 在笛卡尔坐标系中:可由参数斜率和截距(k,b)表示. ② 在极坐标系中:可由参数极经和极角(r,θ)表示. 对于霍夫线变 ...
- Android开发中的OpenCV霍夫直线检测(Imgproc.HoughLines()&Imgproc.HoughLinesP())
本文为作者原创,转载请注明出处(http://www.cnblogs.com/mar-q/)by 负赑屃 //2017-04-21更新: 很多网友希望能得到源码,由于在公司做的,所以不太方便传出来 ...
- 霍夫直线检测 opencv
本次实验是检测图像中的直线,用到了HoughLines()和HoughLinesP()函数,其中HoughLinesP()称为累计概率霍夫变换,实验结果显示累计概率霍夫变换要比标准霍夫变换的效果好.具 ...
- opencv:霍夫直线检测
#include <opencv2/opencv.hpp> #include <iostream> using namespace cv; using namespace st ...
- opencv-霍夫直线变换与圆变换
转自:https://blog.csdn.net/poem_qianmo/article/details/26977557 一.引言 在图像处理和计算机视觉领域中,如何从当前的图像中提取所需要的特征信 ...
- Matlab 霍夫变换 ( Hough Transform) 直线检测
PS:好久没更新,因为期末到了,拼命复习中.复习久了觉得枯燥,玩玩儿霍夫变换直线检测 霍夫变换的基本原理不难,即便是初中生也很容易理解(至少在直线检测上是这样子的). 霍夫变换直线检测的基本原理:(不 ...
- Win8 Metro(C#)数字图像处理--2.38Hough变换直线检测
原文:Win8 Metro(C#)数字图像处理--2.38Hough变换直线检测 [函数名称] Hough 变换直线检测 HoughLineDetect(WriteableBit ...
- OpenCV2马拉松第22圈——Hough变换直线检測原理与实现
计算机视觉讨论群162501053 转载请注明:http://blog.csdn.net/abcd1992719g/article/details/27220445 收入囊中 Hough变换 概率Ho ...
随机推荐
- 【转载】 xavier,kaiming初始化中的fan_in,fan_out在卷积神经网络是什么意思
原文地址: https://www.cnblogs.com/liuzhan709/p/10092679.html =========================================== ...
- 社区6月月报 | Apache DolphinScheduler重要修复和优化记录
各位热爱Apache DolphinScheduler的小伙伴们,社区6月月报更新啦!这里将记录Apache DolphinScheduler社区每月的重要更新,欢迎关注. 月度Merge Stars ...
- dubbo序列化问题(一)浮点数问题
转
dubbo是一个分布式服务框架,在国内比较常用,在开发过程中遇到一个浮点数反序列化问题. 问题描述,当参数是float类型的3.7,反序列化却得到了一个double类型的值:3.70000004768 ...
- 【CMake系列】09-cmake install 一般文件 文件夹 代码文件
上一节,我们学习了项目构建后.目标的安装,本节学习的内容是 对于一般文件,文件夹以及源代码的安装 本节的文件依然使用 file(WRITE xxx.xx) 来创建,不依赖额外的文件 本专栏的实践代码全 ...
- zabbix 自定义用户key与参数userparameters监控监本输出
zabbix在模板中预定义了一些key,但通常情况,并不能满足我们的需求.幸运的是zabbix提供了自定义key的方法,因此我们可以灵活的监控各种我们想要监控的数据. 定义key有两种修改方式: vi ...
- JuiceFS 在多云架构中加速大模型推理
在大模型的开发与应用中,数据预处理.模型开发.训练和推理构成四个关键环节.本文将重点探讨推理环节.在之前的博客中,社区用户 BentoML 和贝壳的案例提到了使用 JuiceFS 社区版来提高模型加载 ...
- Python if __name__ == "__main__" 解释
一种机制,允许脚本以不同的方式运行,这取决于作为独立的程序执行还是作为模块被其他脚本导入.这种机制就是 if __name == "__main__" 其作用是控制某些代码块只在该 ...
- uni-app 商场样式
基于ColorUI-UniApp css样式开发的商城基础模 模板基础功能实现 1.首页今日推荐 点击 会商品加一 2.分类 页面 左右列表联动 3.购物车 商品加减 4.我的 订单管理 账号密码登 ...
- Dockerfile介绍及常用保留指令
从本文开始,咱们将介绍docker的另外一个技术点:dockerfile.我们来看看DockerFile相关的知识点,我们将怎么学习? 1:DockerFile是什么? 2:DockerFile构建过 ...
- 给网站添加Let's Encrypt的免费ssl证书
概要 目前很多浏览器默认都会标记http访问的网站为不安全,https部署已经称为大趋势,我之前利用业余时间搭建了一个网站,本文就以这个域名为基础说明如何给网站加上证书.本文使用的操作系统centos ...