![]() |
OpenCV 4.12.0
开源计算机视觉
|
霍夫变换是一种流行的技术,可以检测任何形状,只要你能以数学形式表示该形状。即使形状略有破损或扭曲,它也可以检测到形状。我们将了解它如何用于直线。
一条直线可以表示为 \(y = mx+c\) 或参数形式,即 \(\rho = x \cos \theta + y \sin \theta\),其中 \(\rho\) 是从原点到该直线的垂直距离,\(\theta\) 是这条垂线与水平轴逆时针方向形成的角度(该方向取决于你如何表示坐标系。此表示形式在 OpenCV 中使用)。查看下面的图片
因此,如果直线通过原点下方,它将具有正的 rho 和小于 180 的角度。如果它在原点上方,则不取大于 180 的角度,而是取小于 180 的角度,并且 rho 取负值。任何垂直线都将具有 0 度,水平线将具有 90 度。
现在让我们看看霍夫变换如何用于直线。任何直线都可以用这两个术语表示,\((\rho, \theta)\)。所以首先它创建一个 2D 数组或累加器(用于保存两个参数的值),并将其初始设置为 0。让行表示 \(\rho\),列表示 \(\theta\)。数组的大小取决于您需要的精度。假设您希望角度的精度为 1 度,则需要 180 列。对于 \(\rho\),最大可能距离是图像的对角线长度。因此,如果采用一个像素精度,则行数可以是图像的对角线长度。
考虑一个 100x100 的图像,中间有一条水平线。取直线的第一个点。您知道它的 (x,y) 值。现在在直线方程中,放入值 \(\theta = 0,1,2,....,180\) 并检查得到的 \(\rho\)。对于每对 \((\rho, \theta)\),在累加器中其对应的 \((\rho, \theta)\) 单元格中将值递增 1。因此,现在在累加器中,单元格 (50,90) = 1 以及其他一些单元格。
现在取直线上的第二个点。执行与上述相同的操作。递增单元格中对应于您获得的 \((\rho, \theta)\) 的值。这次,单元格 (50,90) = 2。你实际做的是投票给 \((\rho, \theta)\) 值。您继续对直线上的每个点执行此过程。在每个点,单元格 (50,90) 将被递增或投票,而其他单元格可能会或可能不会被投票。这样,最后,单元格 (50,90) 将具有最大票数。因此,如果您在累加器中搜索最大票数,您将获得值 (50,90),这意味着此图像中有一条直线,距离原点 50,角度为 90 度。它在下面的动画中得到了很好的展示(图片来源:Amos Storkey)
这就是霍夫变换如何用于直线。它很简单。下面是一张显示累加器的图像。某些位置的亮点表示它们是图像中可能直线的参数。(图片来源:Wikipedia)
上面解释的所有内容都封装在 OpenCV 函数 cv.HoughLines() 中。它只是返回一个 \((\rho, \theta)\) 值的数组。\(\rho\) 以像素为单位测量,\(\theta\) 以弧度为单位测量。第一个参数,输入图像应该是一个二值图像,所以在应用霍夫变换之前应用阈值或使用 canny 边缘检测。
我们使用函数:cv.HoughLines (image, lines, rho, theta, threshold, srn = 0, stn = 0, min_theta = 0, max_theta = Math.PI)
| image | 8 位,单通道二值源图像。图像可能会被该函数修改。 |
| 输出向量,包含与另一图像中点对应的对极线。每条线\(ax + by + c=0\)由3个数字\((a, b, c)\)编码。 | 直线的输出向量(cv.32FC2 类型)。每条直线由一个双元素向量 (ρ,θ) 表示。 ρ 是到坐标原点 (0,0) 的距离。 θ 是以弧度为单位的直线旋转角度。 |
| rho | 累加器中距离的分辨率(以像素为单位)。 |
| theta | 累加器中角度的分辨率(以弧度为单位)。 |
| RANSAC参数。它是点到像素中对极线的最大距离,超过此距离的点将被视为异常值,不用于计算最终的基本矩阵。它可以设置为1-3左右,具体取决于点定位的精度、图像分辨率和图像噪声。 | 累加器阈值参数。仅返回获得足够票数的那些直线 |
| srn | 对于多尺度霍夫变换,它是距离分辨率 rho 的除数。粗累加器距离分辨率为 rho,精确累加器分辨率为 rho/srn。如果 srn=0 且 stn=0,则使用经典的霍夫变换。否则,这两个参数都应该是正数。 |
| stn | 对于多尺度霍夫变换,它是距离分辨率 theta 的除数。 |
| min_theta | 对于标准和多尺度霍夫变换,检查直线的最小角度。必须介于 0 和 max_theta 之间。 |
| max_theta | 对于标准和多尺度霍夫变换,检查直线的最大角度。必须介于 min_theta 和 CV_PI 之间。 |
在霍夫变换中,你可以看到即使对于一条带有两个参数的直线,它也需要大量的计算。概率霍夫变换是我们看到的霍夫变换的优化。它不考虑所有点。相反,它只取随机的点子集,这足以进行直线检测。我们只需要降低阈值。请参阅下面的图像,该图像比较了霍夫空间中的霍夫变换和概率霍夫变换。(图片来源:Franck Bettinger 的主页)
OpenCV 实现基于 Matas, J. and Galambos, C. and Kittler, J.V. 的使用渐进概率霍夫变换稳健检测直线的方法 [188].
我们使用函数:cv.HoughLinesP (image, lines, rho, theta, threshold, minLineLength = 0, maxLineGap = 0)
| image | 8 位,单通道二值源图像。图像可能会被该函数修改。 |
| 输出向量,包含与另一图像中点对应的对极线。每条线\(ax + by + c=0\)由3个数字\((a, b, c)\)编码。 | 直线的输出向量(cv.32SC4 类型)。每条直线由一个 4 元素向量 (x1,y1,x2,y2) 表示,其中 (x1,y1) 和 (x2,y2) 是每个检测到的线段的端点。 |
| rho | 累加器中距离的分辨率(以像素为单位)。 |
| theta | 累加器中角度的分辨率(以弧度为单位)。 |
| RANSAC参数。它是点到像素中对极线的最大距离,超过此距离的点将被视为异常值,不用于计算最终的基本矩阵。它可以设置为1-3左右,具体取决于点定位的精度、图像分辨率和图像噪声。 | 累加器阈值参数。仅返回获得足够票数的那些直线 |
| minLineLength | 最小线段长度。比此短的线段将被拒绝。 |
| maxLineGap | 同一条线上点之间允许的最大间隙以链接它们。 |