当前位置: 代码迷 >> 综合 >> 霍夫圈变换——Hough circle
  详细解决方案

霍夫圈变换——Hough circle

热度:20   发布时间:2024-01-31 01:03:30.0

草鸡详细的hough.circle介绍
一个电脑编程小白的自我成长之路(&_&)嘿嘿。

CvSeq* cvHoughCircles( CvArr* image, void* circle_storage, int method, double dp, double min_dist, double param1=100, double param2=100, int min_radius=0, int max_radius=0 );
def find_pupil_hough(img):"""Finds the pupil using Hugh transform.:param img: Image of an eye:return: x, y coordinates of the centre of the pupil and its radius"""#画hough圈,1参为图片;2参实现函数这里是霍夫梯度下降;3参 dp值 1表示和原图一样的大小和分辨率 2 表示为原图一半大小和分辨率;4参,表示两个圆心之间最小距离;#5参,表示传递给canny的边缘算子的阈值;6参表示圆心累加器阈值;7参,圆半径最小值;8参,圆半径最大值circles = cv2.HoughCircles(img, cv2.HOUGH_GRADIENT, 1, 20,param1=50, param2=30, minRadius=10, maxRadius=200)print(circles)           #  [[[443.5 333.5  65.9]#  [212.5 712.5  62.7]]]circles = np.uint16(np.around(circles))return circles[0, 0][0], circles[0, 0][1], circles[0, 0][2]         # 返回圆圈的x , y , r

image
输入 :必须为8-比特、单通道灰度图像。

8位的单通道灰度图,我们正常看到的屏幕上的彩图,是三通道,R(red,红色)、G(green,绿色)、B(blue,蓝色)这三个通道。每一个通道用8位二进制数即一个字节表示,一个字节含8位二进制数(最大为2的7次方=256)譬如00101011=35,也就是为什么每一个通道像素点的亮度值为0-255(为什么不是256,因为计算机编码是从0开始,到255就是256个数)若是还搞不懂,这个内容后续再详细写,请看cvt.Color篇的博文。

circle_storage / circles (第二段代码中)
检测到的圆存储仓. 可以是内存存储仓 (此种情况下,一个线段序列在存储仓中被创建,并且由函数返回)或者是包含圆参数的特殊类型的具有单行/单列的CV_32FC3型矩阵(CvMat*). 矩阵头为函数所修改,使得它的 cols/rows 将包含一组检测到的圆。如果 circle_storage 是矩阵,而实际圆的数目超过矩阵尺寸,那么最大可能数目的圆被返回
. 每个圆由三个浮点数表示:圆心坐标(x,y)和半径.
第二段代码返回的就是circles[0,0][0]=443.5,circles[0,0][1]=333.5,circles[0,0][2]=65.9分别为圆心坐标(x,y)和半径的值注意是浮点型哈。

method
Hough 变换方式,目前只支持CV_HOUGH_GRADIENT, 这个是目前的hough圈可选的唯一一个梯度下降函数。运用的是圆上某一点切线的的法线,即半径方向。因为圆上任意一个点的法线方向经过圆心。

dp
累加器图像的分辨率。这个参数允许创建一个比输入图像分辨率低的累加器。(这样做是因为有理由认为图像中存在的圆会自然降低到与图像宽高相同数量的范畴)。如果dp设置为1,则分辨率是相同的;如果设置为更大的值(比如2),累加器的分辨率受此影响会变小(此情况下为一半)。dp的值不能比1小。注意:dp越大,累加器的分辨率越低,dp越小,累加器的分辨率越大,但是累加器图像的分辨率来源于原图,所以只能比原图低,比可能比原图高。
Resolution of the accumulator used to detect centers of the circles. For example, if it is 1, the accumulator will have the same resolution as the input image, if it is 2 - accumulator will have twice smaller width and height, etc.

min_dist / 20(第二段python代码中设置的是20)
该参数是让算法能明显区分的两个不同圆之间的最小距离。神马意思呢?意思是 ,区别两个圆的参数,假如被检测图片上有两个圆,这两个圆的圆心距小于这个值,那就认为这两个圆无区别,即会被画到一个圆中,不区别。当这个值设置的越小,那可能检测出的圆就越多,就是区分越严格嘛。
Minimum distance between centers of the detected circles. If the parameter is too small, multiple neighbor circles may be falsely detected in addition to a true one. If it is too large, some circles may be missed.

param1
用于Canny的边缘阀值上限,下限被置为上限的一半。
canny边缘检测,一般步骤:
(1)图片灰度变换
(2)图片平滑处理(也叫消除噪音)有高斯函数法guassion、均值法mean、中值法medium等这个在后面图片处理博文中会详细讲解。
(3)非极大值抑制。原图和处理图进行按位与运算
(4)滞后阈值,这个值是判断处理图的像素点是原图边缘点还是噪声点的区别值
The first method-specific parameter. In case of CV_HOUGH_GRADIENT it is the higher threshold of the two passed to Canny edge detector (the lower one will be twice smaller).

param2
累加器的阀值。这个我的理解是投票数。
The second method-specific parameter. In case of CV_HOUGH_GRADIENT it is accumulator threshold at the center detection stage. The smaller it is, the more false circles may be detected. Circles, corresponding to the larger accumulator values, will be returned first.

min_radius
最小圆半径。被检测图片的需要检测的圆的半径范围中最小圆半径。
Minimal radius of the circles to search for.

max_radius
最大圆半径。被检测图片的需要检测的圆的半径范围中最小圆半径。
Maximal radius of the circles to search for. By default the maximal radius is set to max(image_width, image_height).

现在来讲讲霍夫圈hough.circle原理。
霍夫是谁?管他是谁,肯定不是个中国人。怎么识别圆的我们搞清楚就可以啦。圆的标准方程是这个高中学过的,啥,你上过高中。没事,把他当你老婆记住就行了
【这个高中学过的,啥,你没上过高中或者你不记得啦。没事,把他当你老婆记住就行了】
圆心(a,b),半径r。圆心决定圆的位置,半径决定圆的大小。也就是说,我要识别一个圆或者确定一个圆需要知道圆心和半径,然后霍夫怎么干呢,我吧图片稍微处理一下,然后给边缘的点算切线的法线,然后法线经过圆心,每三个不共线的点就可以确定一个圆心,就这样算。算三个点就可以得到圆心坐标,然后超过这个阈值就认为这些点都在这个圆上,那囊括这些点的圆就是检测出来的圆。但是,这里检测的时候,他巧妙的做了一个坐标系变换,本来我们的圆上的点在(x,y)坐标系中,霍夫他反过来,将圆的方程先理解为在a-b的卡迪尔坐标系下(啥不明白卡迪尔坐标系,原谅我装逼,就是我们初中学的直角坐标系),那该圆的方程就是:
在这里插入图片描述

然后,计算在a-b坐标系下的点(a0,b0),r为半径作圆。如下图:
在这里插入图片描述
本来应该是在整个矩形图片区域内作圆,假设矩形是1048480的矩形,然后在这个矩形里对每一个像素点对一个圆,将这些圆的交点,作计数(通俗说就是投票)很显然,圆形的位置将是所有圆交点计数最多的,看上图给的,比如红色圆有交点,但是计数必然不高,绿色圆经过中间那个大黑点,然后计数也很高(我只画了两个绿色的圆,其他的自己进行脑补哈)。就这样计数最多的被认为是圆心,因为计算机中图片的边缘不是严格的圆,而且图片给的圆很多时候只是近似的圆,也不是严格的圆。我们检测的圆是检测图像最接近的圆。所以,这个迭代计算,那就得作1048480r=503040r个圆,为什么乘个r呢,因为r我们一开始也是不知道的,假设我们给的R的范围是200-300那R迭代就是100次,总共得作50304000个圆,这个计算量不考虑后面的就已经很大了,所以有人想了一个法子,用canny进行边缘提取,那也就是我们会得到上图中黑色的大圆的一个近似图像,然后我们对这个圆里面的点进行迭代,此时运算量就会减少很多。假设这个近似图像的圆形半径是150,那这个图像里的点的是3.14150150,将进行3.14150150100=7065000次迭代,运算降了一个数量级。但是,这个运算量还是很大。然后,有朋友对算法做了优化。不是每个边缘点的切线的法线会经过圆心吗?这样,我每次迭代只需要迭代直线就可以啦,直线是两个参数,圆不是三个参数吗?那我从两个参数,降了一个参数,不是运算又降了一个量级吗?(你肯定说他妈的,又想忽悠俺介么个老实人,明明是3个参数,降成了2个参数,哪有降一个量级。还真告诉你是降了一个量级,这是迭代,假设圆的x坐标从100-150,要运算50次,y坐标从100-130要运算30次,R半径要运算100次,那总共是5030100=150000次,但是同样是直线却只需要50*30=1500次。)至于半径为什么要选范围,如果不选,将从0开始一直变大进行迭代,浪费内存,一幅图中的圆,R不可能超过图的宽和长,所以设置范围是有必要的。也就是min_radius到max_radius范围。累加器阈值param2,不能设置过低,过低的话会检测出很多圆,比如我设置为1,那上图中两个红色圆的交点是不是就被计数为1,则会认为是一个圆心,从图中我们知道这明显是不是真正的圆心。至于param1 的设置,我后面再详细讲,这个和边缘提取时图像的像素亮度值有关。一般我们按默认值100取,对于某些图片我们需要去调。至于其他的参数,上面参数介绍的时候已经讲清楚啦。
好了,文字比较多。看看你老婆护护眼,哈哈@_@。
在这里插入图片描述
啊?!这个不是?那哈面这个内?
在这里插入图片描述

霍夫直线变换的原理,请看这位博主的帖子,写的很详细,也比较好理解,我就不多BB啦;
添加链接描述

参考博文:
https://blog.csdn.net/zhazhiqiang/article/details/51096727?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase

  相关解决方案