1.原理
一条线可以表示为y = mx + c或以参数形式表示为ρ=xcosθ+ysinθ,其中ρ是从原点到该线的垂直距离,而θ是由该垂直线和水平轴形成的角度以逆时针方向测量(该方向随如何表示坐标系而变化)
任何一条线都可以用(ρ,θ)这两个术语表示。因此,首先创建2D数组或累加器(以保存两个参数的值),并将其初始设置为0。让行表示ρ,列表示θ。阵列的大小取决于所需的精度。假设您希望角度的精度为1度,则需要180列。对于ρ,最大距离可能是图像的对角线长度。因此,以一个像素精度为准,行数可以是图像的对角线长度。
考虑一个 100x100 的图像,中间有一条水平线。取直线的第一点。您知道它的 (x,y) 值。现在在线性方程式中,将值θ= 0,1,2,… 180放进去,然后检查得到ρ。对于每对(ρ,θ),在累加器中对应的(ρ,θ)单元格将值增加1。所以现在在累加器中,单元格(50,90)= 1以及其他一些单元格。现在,对行的第二个点。执行与上述相同的操作。递增(\rho,\theta)对应的单元格中的值。这次,单元格 (50,90)=2 。实际上,您正在对(ρ,θ)值进行投票。您对线路上的每个点都继续执行此过程。在每个点上,单元格(50,90)都会增加或投票,而其他单元格可能会或可能不会投票。这样一来,最后,单元格(50,90)的投票数将最高。因此,如果您在累加器中搜索最大票数,则将获得(50,90)值,该值表示该图像中的一条线与原点的距离为50,角度为90度
2.OpenCV实现霍夫线变换
主要使用cv.HoughLines()函数来实现。
cv.HoughLines(img, rho, theta, threshold )
参数如下:
- img:输入的图像,Canny提取后的边界数据
- rho:距离分辨率,即ρ范围
- theta:角度范围,即θ范围
- threshold:累加器阈值(最小线长)
- 返回一个:math:(ρ,θ) 值的数组
代码示例:
import numpy as np
import cv2 as cv
img = cv.imread(cv.samples.findFile('C:\\Users\\dell\\Desktop\\prac files\\prac7.jpg'))
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
edges = cv.Canny(gray,50,150,apertureSize = 3)
lines = cv.HoughLines(edges,1,np.pi/180,200)
for line in lines:
rho, theta = line[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))
cv.line(img, (x1, y1), (x2, y2), (0, 0, 255), 2)
cv.imshow("prac", img)
cv.waitKey(0)
cv.destroyAllWindows()
3.概率霍夫变换
主要使用cv2.HoughLinesP()函数来实现。
cv2.HoughLinesP(image, rho, theta, threshold, lines=None, minLineLength=None, maxLineGap=None)
参数如下:
- image: 必须是二值图像,推荐使用canny边缘检测的结果图像
- rho: 线段以像素为单位的距离精度,double类型的,推荐用1.0
- theta: 线段以弧度为单位的角度精度,推荐用numpy.pi/180
- threshod:累加平面的阈值参数,int类型,超过设定阈值才被检测出线段,值越大,基本上意味着检出的线段越长,检出的线段个数越少
- lines:这个参数的意义未知
- minLineLength:线段以像素为单位的最小长度,根据应用场景设置
- maxLineGap:同一方向上两条线段判定为一条线段的最大允许间隔(断裂),超过了设定值,则把两条线段当成一条线段,值越大,允许线段上的断裂越大,越有可能检出潜在的直线段
代码示例:
import numpy as np
import cv2 as cv
img = cv.imread(cv.samples.findFile('C:\\Users\\dell\\Desktop\\prac files\\prac7.jpg'))
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
edges = cv.Canny(gray,50,150,apertureSize = 3)
lines = cv.HoughLinesP(edges,1,np.pi/180,100,minLineLength=100,maxLineGap=10)
for line in lines:
x1, y1, x2, y2 = line[0]
cv.line(img, (x1, y1), (x2, y2), (0, 255, 0), 2)
cv.imshow("prac", img)
cv.waitKey(0)
cv.destroyAllWindows()