opencv-python霍夫变换
1 霍夫线检测原理
霍夫变换常用来提取图像中的直线和圆等几何形状。
在笛卡尔坐标系中,直线可以表示为 y=kx+q 也就是说通过变量k,q可以确定一条直线,把直线写成关于k,q的函数,进行空间转换,转换后的空间称为霍夫空间。

也就是说:笛卡尔坐标系中的一条线对应了霍夫空间的一个点。反过来,霍夫空间的一条线对应了笛卡尔坐标系的一个点。

如果笛卡尔坐标系中的点共线,那么这些点在霍夫空间中对应的直线应该交于一点。

如果是判断多个点是否共线的话,就尽可能找霍夫空间中更多直线相交的点。即霍夫坐标空间中选择尽可能多的直线汇成的点,将其对应回笛卡尔坐标系中的直线,基本上可以完成直线检测。

但是如果是垂直于y轴的直线,比如x=2,那么k,q就不好确定了。为了解决这种情况,把笛卡尔坐标系转换到极坐标系是比较好的选择。

因此,只需要指知道霍夫空间中交点的位置,就可以得到原坐标系下的直线。

实现流程如下:

2 霍夫线检测
opencv中霍夫线检测使用的api是 HoughLines(img,rho,theta,threshold)。检测的图像需要二值化或者进行canny边缘检测。threshold:阈值,只有高于阈值的累加器的值才是直线。
import cv2
import numpy as np
img = cv2.imread('./contours.png')
img_copy = img.copy()
img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
edges =cv2.Canny(img_gray,50,150) # canny边缘检测
cv2.imshow('edges',edges)
lines = cv2.HoughLines(edges,1,np.pi/180,100) #霍夫直线检测,threshold越小,越容易检测到更多的直线
print(lines)
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))
cv2.line(img_copy,(x1,y1),(x2,y2),[0,0,255]) #绘制直线
cv2.imshow('img_hough',img_copy)
cv2.imshow('img',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
检测结果如下:

3 霍夫圆检测

# 霍夫圆检测
import cv2
import numpy as np
img = cv2.imread('./circle.jpg')
img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
img_gray = cv2.medianBlur(img_gray,3) #中值滤波
res_img = np.zeros(img.shape[:],np.uint8)
res_img[:] = 255
print(img.shape)
#edges = cv2.Canny(img_gray,50,150) #不需要进行canny边缘检测,否则霍夫检测不出来圆,返回none
circles = cv2.HoughCircles(img_gray,cv2.HOUGH_GRADIENT,1,100,param2=50) #霍夫圆检测,返回圆心和半径的list
circles = np.int0(np.around(circles)) # 把结果转换为int整数
for i in circles[0,:]:
cv2.circle(res_img,(i[0],i[1]),i[2],[0,0,255],2) #根据检测的结果绘制圆
print(circles)
cv2.imshow('img',img)
cv2.imshow('res_img',res_img)
#cv2.imshow('edges',edges)
cv2.waitKey(0)
cv2.destroyAllWindows()
检测结果如下:


浙公网安备 33010602011771号