7.2. 霍夫线变换

7.2.1. 目标

在本章中,
-我们将理解Hough变换的概念。-我们将看到如何使用它来检测图像中的线条。-我们将看到以下功能: cv2.小时线()cv2.小时线SP()

7.2.2. 理论

Hough变换是一种流行的检测任意形状的技术,如果你能用数学形式表示该形状的话。它可以检测到形状,即使它是破碎或扭曲了一点。我们来看看这条线是怎么工作的。

一条线可以表示为 \(y = mx+c\) 或参数形式,如 \(\rho = x \cos \theta + y \sin \theta\) 在哪里? \(\rho\) 是从原点到直线的垂直距离,并且 \(\theta\) 是由这条垂直线和水平轴形成的角度,以逆时针方向测量(该方向随表示坐标系的方式而变化)。这个表示在OpenCV中使用)。检查下图:

因此,如果直线在原点下方通过,它将有一个正的rho和小于180的角度。如果它在原点上方,而不是取大于180的角度,则取小于180的角度,并且取rho为负。任何垂直线将有0度,水平线将有90度。

现在让我们看看Hough变换是如何处理直线的。任何一行都可以用这两个词来表示, \((\rho, \theta)\) . 因此,首先它创建一个二维数组或累加器(用于保存两个参数的值),并最初设置为0。让行表示 \(\rho\) 列表示 \(\theta\) . 数组的大小取决于您需要的精度。假设您希望角度的精度为1度,则需要180列。为了 \(\rho\) ,可能的最大距离是图像的对角线长度。所以取一个像素的精度,行数可以是图像的对角线长度。

考虑一个100x100图像,中间有一条水平线。走这条线的第一个点。你知道它的(x,y)值。现在在直线方程中,把值 \(\theta = 0,1,2,....,180\) 并检查 \(\rho\) 你明白了。为每一个 \((\rho, \theta)\) 对,你在它对应的累加器中增加一个值 \((\rho, \theta)\) 细胞。所以现在在累加器中,单元格(50,90)=1和其他一些单元格。

现在在直线上取第二个点。按上述步骤操作。增加单元格中与 \((\rho, \theta)\) 你知道。这次,单元格(50,90)=2。你实际上做的是投票 \((\rho, \theta)\) 价值观。你继续这一过程的每一个点上的线。在每一点上,单元(50,90)将递增或向上投票,而其他单元可以或不可以向上投票。这样,在最后,单元格(50,90)将拥有最大投票权。所以如果你在累加器中搜索最大投票数,你会得到一个值(50,90),也就是说,在这个图像中有一条线,距离原点50度,角度90度。它在下面的动画中显示得很好(图片礼貌: Amos Storkey

这就是hough变换的原理。它很简单,也许你可以自己用Numpy实现它。下面是显示累加器的图像。某些位置的亮点表示它们是图像中可能线条的参数。(图片礼貌: Wikipedia

7.2.3. OpenCV中的Hough变换

上面解释的所有内容都封装在OpenCV函数中, cv2.小时线() . 它只返回一个数组 \((\rho, \theta)\) 价值观。 \(\rho\) 以像素和 \(\theta\) 以弧度为单位。第一个参数,输入的图像应该是二值图像,所以在应用hough变换之前应用阈值或canny边缘检测。第二和第三个参数是 \(\rho\)\(\theta\) 准确度。第四个论点是 \(threshold\) ,这意味着它应该获得的最低票数应该被视为一条线。记住,票数取决于这条线上的点数。所以它代表了应该检测的最小行长度。

>>> import cv2
>>> import numpy as np
>>>
>>> img = cv2.imread('/cvdata/dave.jpg')
>>> gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
>>> edges = cv2.Canny(gray,50,150,apertureSize = 3)
>>>
>>> lines = cv2.HoughLines(edges,1,np.pi/180,200)
>>> for rho,theta in lines[0]:
>>>     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.imwrite('xx_houghlines3.jpg',img)
True

image0

检查以下结果:

7.2.4. 概率Hough变换

在hough变换中,你可以看到,即使一行有两个参数,也需要大量的计算。概率Hough变换是我们所看到的Hough变换的一种优化。它没有考虑所有的点,而是只考虑点的随机子集,这就足以进行直线检测。只是我们得降低门槛。下面的图片比较了Hough变换和Hough空间中的概率Hough变换。(图片礼貌: Franck Bettinger’s home page

OpenCV的实现基于Matas,J.和Galambos,C.和Kittler,J.V.使用渐进概率Hough变换对直线进行鲁棒检测。。使用的函数是 cv2.小时线SP() . 它有两个新的论点。
- minLineLength - Minimum length of line. Line segments shorter than this are rejected. - maxLineGap - Maximum allowed gap between line segments to treat them as single line.

最好的是,它直接返回直线的两个端点。在前面的例子中,你只得到了直线的参数,你必须找到所有的点。在这里,一切都是直接和简单的。

>>> import cv2
>>> import numpy as np
>>>
>>> img = cv2.imread('/cvdata/dave.jpg')
>>> gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
>>> edges = cv2.Canny(gray,50,150,apertureSize = 3)
>>> minLineLength = 100
>>> maxLineGap = 10
>>> lines = cv2.HoughLinesP(edges,1,np.pi/180,100,minLineLength,maxLineGap)
>>> for x1,y1,x2,y2 in lines[0]:
>>>     cv2.line(img,(x1,y1),(x2,y2),(0,255,0),2)
>>>
>>> cv2.imwrite('xx_houghlines5.jpg',img)
True

image0

结果如下:

7.2.5. 额外资源

  1. Hough Transform on Wikipedia

7.2.6. 练习