一、原理
推文:Opencv2.4.9源码分析——HoughCircles
图形可以用一些参数进行表示,标准霍夫变换的原理就是把图像空间转换成参数空间(即霍夫空间),例如霍夫变换的直线检测就是在距离-角度空间内进行检测。圆可以表示成:
(x-a)2+(y-b)2=r2
其中a和b表示圆心坐标,r表示圆半径,因此霍夫变换的圆检测就是在这三个参数组成的三维空间内进行检测。[ a,b,theta]
霍夫变换把标准霍夫变换的三维霍夫空间缩小为二维霍夫空间,因此无论在内存的使用上还是在运行效率上,霍夫变换都远远优于标准霍夫变换。但该算法有一个不足之处就是由于圆半径的检测完全取决于圆心的检测,因此如果圆心检测出现偏差,那么圆半径的检测肯定也是错误的。
二、相关函数
1、HoughCircles函数
def HoughCircles(image, method, dp, minDist, circles=None, param1=None, param2=None, minRadius=None, maxRadius=None):
cv.HoughCircles(gray,cv.HOUGH_GRADIENT,1,20,param1=50,param2=30,minRadius=0,maxRadius=0)
image:输入图像 (灰度图)
method:指定检测方法. 现在OpenCV中只有霍夫梯度法
dp:累加器图像的反比分辨=1即可默认
minDist = src_gray.rows/8: 检测到圆心之间的最小距离,这是一个经验值。这个大了,那么多个圆就是被认为一个圆。
param_1 = 200: Canny边缘函数的高阈值
param_2 = 100: 圆心检测阈值.根据你的图像中的圆大小设置,当这张图片中的圆越小,那么此值就设置应该被设置越小。当设置的越小,那么检测出的圆越多,在检测较大的圆时则会产生很多噪声。所以要根据检测圆的大小变化。
min_radius = 0: 能检测到的最小圆半径, 默认为0.
max_radius = 0: 能检测到的最大圆半径, 默认为0
2、cv.circle
circle(CV_IN_OUT Mat& img, Point center, int radius, const Scalar& color, int thickness=1, int lineType=8, int shift=0);
img为图像,单通道多通道都行,不需要特殊要求
center为画圆的圆心坐标
radius为圆的半径
color为设定圆的颜色,比如用CV_RGB(255,0,0)设置为红色, CV_RGB(255,,255)设置为白色,CV_RGB(0,,0)设置为黑色
thickness为设置圆线条的粗细,值越大则线条越粗,为负数则是填充效果
三、代码实现
1 霍夫圆检测
2 1.加载一幅图像
3 2.执行高斯模糊以降低噪声:GaussianBlur
4 3.转成灰度图:cvtColor
5 4.执行霍夫圆变换:HoughCircles
6 5.在窗体中显示检测到的圆
7
8 import numpy as np
9 import cv2 as cv
10
11 def circle(image):
12
13 #模糊降噪方法一:高斯双边模糊,不太好调节,霍夫噪声敏感,所以要先消除噪声
14 #arg
15 # 输入图像
16 #d(像素邻域直径),-1或0是表示根据sigmaspace自动计算
17 #sigemacolor颜色标准差
18 #sigmaspace空间标准差
19 dst = cv.bilateralFilter(image,0,150,5)
20 cv.imshow('bilate_filter',dst)
21
22 #模糊降噪方法二:均值迁移,EPT边缘保留滤波,霍夫噪声敏感,所以要先消除噪声
23 #arg
24 # 输入图像
25 # 漂移物理空间半径 (越大,细节丢失越多)
26 # 漂移色彩空间半径
27 dst = cv.pyrMeanShiftFiltering(image,5,100)
28 cv.imshow('mean_fileter',dst)
29
30 # 模糊降噪方法三:使用高斯模糊,修改卷积核ksize也可以检测出来
31 #arg
32 # 输入图像
33 # 高斯核大小(正、奇数),为(0,0)时根据sigma自动计算
34 # sigmax高斯核函数在x方向的标准偏差,还有sigmay的但是不写的话,可以根据sigmax计算出来,然后高斯核也自动计算出来了
35 dst = cv.GaussianBlur(image,(13,15),15)
36 cv.imshow('gaussianblur',dst)
37
38 gray = cv.cvtColor(dst,cv.COLOR_BGR2GRAY)
39 circles = cv.HoughCircles(gray,cv.HOUGH_GRADIENT,1,20,param1=50,param2=30,minRadius=0,maxRadius=0)
40 #返回的circle:np.ndarray,shape:(1,9,3) 最后一维有三个数(圆心坐标x,圆心坐标y,半径)
41 circles = np.uint16(np.around(circles)) #around对数据四舍五入,为整数
42 # print(circles.shape)
43 # print(type(circles))
44 for i in circles[0,:]: #因为circles第一维只有一个数组
45 print(type(i))
46 print(i.shape)
47 cv.circle(image,(i[0],i[1]),i[2],(0,0,255),2) #圆心坐标x:i[0];圆心坐标y:i[1],半径:i[2]
48 cv.circle(image,(i[0],i[1]),2,(255,0,0),2) #画的是圆心,点个点,半径很小是2,相当于在圆心处点了一个点
49 cv.imshow('detect_circle',image)
50
51 img = cv.imread('circle.png')
52 cv.imshow('circle',img)
53 circle(img)
54 cv.waitKey(0)
55 cv.destroyAllWindows()