OpenCV 4.10.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)
这是霍夫变换对直线进行工作的方式。它很简单,你也许可以通过自己使用 NumPy 来实现它。下方是显示累加器的图像。某些位置的亮斑表明它们是图像中可能直线的参数。(图像致谢:维基百科)
上述所有解释都封装在 OpenCV 函数 cv.HoughLines() 中。它简单地返回一个 :math:(rho, theta)` 值的数组。\(\rho\) 以像素为单位测量,\(\theta\) 以弧度为单位测量。第一个参数,输入图像应该是二进制图像,因此在应用霍夫变换之前应用阈值或使用 Canny 边缘检测。第二个和第三个参数分别是 \(\rho\) 和 \(\theta\) 精度。第四个参数是阈值,这意味着它是作为直线考虑时应该获得的最低票数。记住,票数取决于直线上的点数。所以它表示应该检测到的最小直线长度。
查看以下结果
在霍夫变换中,你可以看到即使对于包含两个参数的线,它的计算量也非常大。概率霍夫变换是对我们所看到的霍夫变换的优化。它不考虑所有点。相反,它只考虑随机子集的点,对于线检测来说,这已经足够了。我们只需降低阈值。请看下图,它比较了霍夫变换与概率霍夫变换在霍夫空间中的差异。(图片由:Franck Bettinger's home page 提供)
OpenCV 实现基于 Matas、J. 和 Galambos、C. 和 Kittler、J.V. 撰写的使用渐进概率霍夫变换鲁棒检测线。 [185]。使用的函数是 cv.HoughLinesP()。它有两个新参数。
最好的地方是,它直接返回线段的两个端点。在上一个案例中,你只能获取线的参数,并且需要自己找出所有的点。这里,一切都直接简单。
查看下面的结果