任何一条线都可以用(ρ,θ)这两个术语表示。因此,首先创建2D数组或累加器(以保存两个参数的值),并将其初始设置为0。让行表示ρ,列表示θ。阵列的大小取决于所需的精度。假设您希望角度的精度为1度,则需要180列。对于ρ,最大距离可能是图像的对角线长度。因此,以一个像素精度为准,行数可以是图像的对角线长度。
考虑一个100x100的图像,中间有一条水平线。取直线的第一点。您知道它的(x,y)值。现在在线性方程式中,将值θ= 0,1,2,… 180放进去,然后检查得到ρ。对于每对(ρ,θ),在累加器中对应的(ρ,θ)单元格将值增加1。所以现在在累加器中,单元格(50,90)= 1以及其他一些单元格。
现在,对行的第二个点。执行与上述相同的操作。递增(ρ,θ)对应的单元格中的值。这次,单元格(50,90)=2。实际上,您正在对(ρ,θ)值进行投票。您对线路上的每个点都继续执行此过程。在每个点上,单元格(50,90)都会增加或投票,而其他单元格可能会或可能不会投票。这样一来,最后,单元格(50,90)的投票数将最高。因此,如果在累加器中搜索最大票数,则将获得(50,90)值,该值表示该图像中的一条线与原点的距离为50,角度为90度。
使用标准Hough变换在二值图像中查找线条
HoughLines(image, rho, theta, threshold[, lines[, srn[, stn[, min_theta[, max_theta]]]]]) -> lines
def line_detection(image):
"""霍夫变换直线检测"""
gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
edges = cv.Canny(gray, 50, 150, apertureSize=3)
# cv2.HoughLines()返回值就是(ρ,θ)。ρ 的单位是像素,θ 的单位是弧度。
# 这个函数的第一个参数是一个二值化图像,所以在进行霍夫变换之前要首先进行二值化,或者进行 Canny 边缘检测。
# 第二和第三个值分别代表 ρ 和 θ 的精确度。第四个参数是阈值,只有累加其中的值高于阈值时才被认为是一条直线,
# 也可以把它看成能 检测到的直线的最短长度(以像素点为单位)。
lines = cv.HoughLines(edges, 1, np.pi / 180, 200)
# print(lines):
for line in lines:
# print(type(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(image, (x1, y1), (x2, y2), (0, 0, 255), 2)
cv.imshow("line_detection", image)
结果:
注意: 当检测不到图片时,lines为None,这时候程序会报错。建议加上if判断。
概率霍夫变换对基本霍夫变换算法进行了一些修正,是霍夫变换算法的优化。它没有考虑所有的点。相反,它只需要一个足以进行线检测的随机点子集即可。
为了更好地判断直线(线段),概率霍夫变换算法还对选取直线的方法作了两点改进:
所接受直线的最小长度。如果有超过阈值个数的像素点构成了一条直线,但是这条直线很短,那么就不会接受该直线作为判断结果,而认为这条直线仅仅是图像中的若干个像素点恰好随机构成了一种算法上的直线关系而已,实际上原图中并不存在这条直线。
接受直线时允许的最大像素点间距。如果有超过阈值个数的像素点构成了一条直线,但是这组像素点之间的距离都很远,就不会接受该直线作为判断结果,而认为这条直线仅仅是图像中的若干个像素点恰好随机构成了一种算法上的直线关系而已,实际上原始图像中并不存在这条直线。
用概率Hough变换在二值图像中查找线段
HoughLinesP(image, rho, theta, threshold[, lines[, minLineLength[, maxLineGap]]]) -> lines
def line_detection_possible(image):
"""概率霍夫变换直线检测"""
gray = cv.cvtColor(image, 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(image, (x1, y1), (x2, y2), (0, 255, 0), 2)
cv.imshow('line_detection_possible', image)
结果:
参考链接:
使用Hough变换在灰度图像中查找圆
HoughCircles(image, method, dp, minDist[, circles[, param1[, param2[, minRadius[, maxRadius]]]]]) -> circles
def circle_detection(image):
"""霍夫圆检测"""
# 均值迁移滤波,因为霍夫圆检测对噪声敏感,sp,sr为空间域核与像素范围域核半径
dst = cv.pyrMeanShiftFiltering(image, 10, 100)
gray = cv.cvtColor(dst, cv.COLOR_BGR2GRAY)
circles = cv.HoughCircles(gray, cv.HOUGH_GRADIENT, 1, 20, param1=50, param2=30, minRadius=0, maxRadius=0)
circles = np.uint16(np.around(circles))
# print(circles.shape)
for i in circles[0, :]: # draw the outer circle
cv.circle(image, (i[0], i[1]), i[2], (0, 255, 0), 2) # 画圆
cv.circle(image, (i[0], i[1]), 2, (0, 0, 255), 3) # 画圆心
cv.imshow('detected circles', image)
结果:
注意: 霍夫圆检测对噪声敏感,使用霍夫圆检测之前,需要先对图片进行滤波降噪处理。
参考链接: