opencv-python霍夫变换

发布时间 2023-07-30 17:48:02作者: 寒水浮云

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()

 检测结果如下: