霍夫变换是一种特征提取术,在了解霍夫变换 霍夫检测之前 需要首先明白什么是霍夫空间:以圆形举例子,弄明白形状的原理,直线的变换与检测也就不难理解 霍夫空间,是一种三维空间,三个坐标分别为圆的横纵坐标,Z轴坐标为半径,所以霍夫圆变换的实质过程就是从二维空间的圆拓展到三维空间
霍夫圆检测:应用:识别红绿灯中信号灯(圆形)物体
在检测圆之前,需要做好边缘检测,这个步骤在Opencv的函数已经内置了,使用Canny算子进行边缘检测,参数需要自行调整
霍夫梯度法:
**检测原理简要概括:模向量 ,垂直于圆心,相交于一点,确定圆心
首先找到圆心 然后寻找半径
估计圆心步骤:
1.把原图做一次 Canny 边缘检测,得到边缘检测的二值图。
2.对原始图像执行一次 Sobel 算子,计算出所有像素的邻域梯度值。
3.初始化圆心空间 N(a,b),令所有的 N(a,b)=0。
4.遍历 Canny 边缘二值图中的所有非零像素点,沿着梯度方向 ( 切线的垂直方向 )画线,将线段经过的所有累加器中的点 (a,b) 的 N(a,b)+=1。 使用的累加器类似于C语言中的counter
5.每个点的counter大小和阈值做比较,如果大于该值,找到圆心,确定一个圆
确定圆心后,寻找半径:
估计半径(针对某一个圆心 (a,b))
1.计算 Canny 图中所有非 0 点距离圆心的距离。
2.距离从小到大排序,根据阈值,选取合适的可能半径(比如 3 和 3.5 都被划为半径值 3 中)。
3.初始化半径空间 r, N®=0。
4.遍历 Canny 图中的非 0 点,N( 距离 )+=1。
5.统计得到可能的半径值(N® 越大,说明这个距离值出现次数越多,越有可能是半径值)。
函数各个参数的意义:HoughCircle:
1:images 输入的图像
2:circles 输出的图像,圆的输出矢量
3.method,使用方法,默认为1,代表霍夫梯度下降
4.dp 分辨率,默认为1,两图分辨率相同
5.minDist 若两圆心距离小于该值 则认为两个圆属于同一个圆
6.para1,Canny算子的阈值
7.para2, 某点是否为圆心的判断阈值,直线相交阈值,大于该值,才能被认为筛选出来的一个圆
8.minradius 半径最小值 默认为0
9.maxradius 半径最大值 默认为0
代码实战:
原图:
调整代码之前:
调整参数以后:
准确率做到了一一对应,圆心的准确率一些图形吻合的比较好,一些还需要调参
开源代码:
// A code block
import cv2
import numpy as np
img = cv2.imread(r"C:UsersWM202Picturescircle.jpg")
GrayImage=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
GrayImage= cv2.medianBlur(GrayImage,5)
ret,th1 = cv2.threshold(GrayImage,127,255,cv2.THRESH_BINARY)
th2 = cv2.adaptiveThreshold(GrayImage,255,cv2.ADAPTIVE_THRESH_MEAN_C,
cv2.THRESH_BINARY,3,5)
th3 = cv2.adaptiveThreshold(GrayImage,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
cv2.THRESH_BINARY,3,5)
kernel = np.ones((5,5),np.uint8)
erosion = cv2.erode(th2,kernel,iterations=1)
dilation = cv2.dilate(erosion,kernel,iterations=1)
imgray=cv2.Canny(erosion,30,100)
circles = cv2.HoughCircles(imgray,cv2.HOUGH_GRADIENT,1,40,
param1=50,param2=10,minRadius=10,maxRadius=80)
circles = np.uint16(np.around(circles))
for i in circles[0,:]:
# draw the outer circle
cv2.circle(img,(i[0],i[1]),i[2],(0,255,0),2)
# draw the center of the circle
cv2.circle(img,(i[0],i[1]),2,(0,0,255),3)
print(len(circles[0,:]))
cv2.namedWindow("detected circles",cv2.WINDOW_NORMAL )
cv2.imshow('detected circles',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
如果你在学习这一部分的时候 或者在调试代码的时候有遇到任何的问题,欢迎留言评论!



