欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

在OpenCV里实现霍夫圆检测2

程序员文章站 2022-07-14 11:18:56
...

霍夫圆标准算法如下:

在OpenCV里实现霍夫圆检测2

但是上面的算法实在太慢了,因为计算量特别惊人,因此基于梯度的霍夫圆检测就是对标准霍夫圆检测的改进。前面也讨论过使用尺规作图时,可以有三点不共线垂直平分线的方法,其实垂值平分线给我们一个提示,就是只要找到法线,就可以找到圆心,有了圆心的位置再去找半径就容易多了。这样比前面蛮力计算要快很多。如果我们再把垂直平分线往外面推,如下图所示:

在OpenCV里实现霍夫圆检测2

这时两点的连线就变成了圆上一点的切线了,而这时垂直平分线就变成圆上一点的法线。如下图所示:

在OpenCV里实现霍夫圆检测2

从这里得到一个事实,就是同一个圆的所有法线都是交于圆心上,那么就是说只要我们在圆周上找到法线,然后再找到交点,此点就圆心了。接着下来的问题就是怎么样找到法线?前面学习过边缘识别时使用Sobel算子来计算梯度,那么就可以采用这个方法来算出每一点的梯度,其实这个梯度方向就是法线向量的角度。接着下来根据法线的方向,就有事情可做了。假如我们要计算圆的半径有一个最大最小的范围,那么在圆周上一点,可以一点一点地向法线方向两端画射线,相当于创建一个二维计数器,在法线两个方向上每移动一个像素点,就在这个二维计数器上增加一,相当于投票一票。等把圆周上所有的点都遍历之后,就可以在二维计数器找到计数最大的位置,然后从大到小来排序,就把这些点当作可能圆心点坐标。

 

接然下来就是对半径进行计数投票了,有了圆心就可以计算圆心到每个圆周上点的半径,如果半径一样的计数器增加一,最后就可以认为半径相等最多像素点的坐标点为圆心点。如下图:

在OpenCV里实现霍夫圆检测2

在上图里,半径相等有两个点A、B,而C点的半径只有一个点,这样就可以认为A、B共圆,并且半径是OA=OB。因此通过上面两步的算法就可以确认圆的圆心和半径,那么对于圆的识别就算完成了。

在OpenCV里的大体算法如下:

I、估计圆心

 

         1、把原图做一次Canny边缘检测,得到边缘检测的二值图

 

         2、对原始图像执行一次Sobel算子,计算出所有像素的邻域梯度值

 

         3、初始化圆心空间N(a,b)计数器,令所有的N(a,b)=0

 

         4、遍历Canny边缘二值图中的所有非零像素点,沿着梯度方向画线,将线段经过的所有累加器中的点(a,b)的N(a,b)+=1

 

         5、统计排序N(a,b) 计数器,得到可能的圆心

 

    II、估计半径(针对某一个圆心a,b)

 

         1、计算Canny图中所有非0点距离圆心的距离

 

         2、距离从小到大排序,根据阈值,选取合适的可能半径(比如3和3.5都被划为半径值3中)

 

         3、初始化半径空间r,N(r)=0

 

         4、遍历Canny图中的非0点,对于点所满足的半径r,N(r)+=1

 

         5、统计得到可能的半径值

有了上面的知识,来看一下OpenCV里的HoughCircles函数定义:

在OpenCV里实现霍夫圆检测2

image:输入图像

 

circles:检测的圆形,(a,b,r)的参数集合

 

method:检测使用的方法,目前OpenCV只提供了CV_HOUGH_GRADIENT方法,即霍夫梯度法

 

dp:图像像素分辨率与参数空间分辨率的比值(官方文档上写的是图像分辨率与累加器分辨率的比值,它把参数空间认为是一个累加器,毕竟里面存储的都是经过的像素点的数量),dp=1,则参数空间与图像像素空间(分辨率)一样大,dp=2,参数空间的分辨率只有像素空间的一半大

 

minDist:两个圆心之间的最小距离。这个距离设置过小,会导致本来属于一个圆上的点被分散成几个小圆,过大则导致部分小圆检测不出来

 

param1:CV_HOUGH_GRADIENT过程中执行Canny边缘检测的阈值

 

param2:参数空间阈值(即至少多少点经过该参数表示的圆),最少投票数

 

minRadius:半径最小值

 

maxRadius:半径最大值

 

用下面的例子来演示这个函数的使用:

#python 3.7.4,opencv4.1
#蔡军生 https://blog.csdn.net/caimouse/article/details/51749579
#
import cv2
import numpy as np
from scipy import signal
import math

#图片的路径
imgname = "rmb2.png"

#读取图片
image = cv2.imread(imgname, cv2.IMREAD_COLOR)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

#图片的高度和宽度
h,w = image.shape[:2]
print('imagesize={}-{}'.format(w,h))

img_blur = cv2.medianBlur(gray, 5)
circles = cv2.HoughCircles(img_blur, cv2.HOUGH_GRADIENT, 1, 100,
                           param1=200, param2=60, minRadius=10, maxRadius=200)
if circles is not None:
    circles = np.uint16(np.around(circles))
    for i in circles[0, :]:
        # 
        cv2.circle(image, (i[0], i[1]), i[2], (0, 255, 0), 2)
        # 
        cv2.circle(image, (i[0], i[1]), 2, (0, 0, 255), 3)
#
cv2.imshow("Image",image)

cv2.waitKey(0)
cv2.destroyAllWindows()

结果输出如下:

在OpenCV里实现霍夫圆检测2

https://blog.csdn.net/caimouse/article/details/51749579

 

相关标签: opencv