🍊作者简介:秃头小苏,致力于用最通俗的语言描述问题
🍊往期回顾:霍夫直线检测原理详解 霍夫直线检测代码实战
🍊近期目标:拥有2000粉丝
🍊支持小苏:点赞👍🏼、收藏⭐、留言📩
霍夫圆检测原理+实战
霍夫圆检测原理
在之前已经详细介绍过霍夫直线检测的原理了,这次我们来简单的谈谈霍夫圆检测的原理并进行实战演练。在霍夫直线检测中我已经非常详细的给出了直线检测的原理,不清楚的请先去了解。🥗🥗🥗
这篇文章我可能不会把原理介绍的非常详细,但肯定会很通俗。【因为用通俗的语言描述问题是我写作的宗旨嘛】其实和直线检测原理是非常类似的,我将用直线检测和圆检测做对比让大家直观上的理解霍夫圆检测。🍒🍒🍒
在霍夫直线检测中我们的期待求得的未知量是两个,斜率k和截距b;而霍夫圆检测的未知量则变成了三个,分别为圆心坐标(a,b)和半径r。在霍夫直线检测中我们的参数空间是二维的,那么霍夫圆检测的参数空间应该就为三维的,因为有三个未知参数嘛🥙🥙🥙
不知道这样的描述大家能不能理解哈,再换一种表述方式。我们知道在图像空间的x-y坐标系中,圆的方程为:(x-a)2+(y-b)2=r2。现我们将其转换到a-b-r的三维参数空间,其表达式为:(a-x)2+(b-y)2=r2。在霍夫直线检测原理中我们给出了下列结论:
- 图像空间x-y中的一点对应于参数空间k-b中的一条直线。
- 图像空间中的一条直线对应于参数空间k-b中的一个点。
那么对应圆检测来说有怎样的结论呢?我们都可以思考思考。类比思考起来也很容易哈,==对应图像空间圆上的一点(x0,y0)对应于参数空间应该是一个三维的锥面。==这个三维曲面如下:即不同的半径r下都会对应一个圆,这样就构成了一个圆锥面。【这里所有不同r下的圆心坐标都为(x0,y0)】
那么我们若取图像空间圆上的两点,则在参数空间中对应于两个锥面。以此类推,若取图像空间圆上的所有点,对应于参数空间将会有许多锥面,且这些锥面会有一个共同的交点坐标M(a , b , r ),则根据这个M点坐标我们就可以求出原图像空间中的圆啦🍋🍋🍋
是不是发现和霍夫直线检测的思想是差不多的,但是这里存在一个找公共交点的问题,对于上述的思路较消耗较多的计算量,因此对霍夫圆检测又有了改进,是基于梯度来计算的,这里我更期待的可能是怎么用代码实现圆的检测,因此这儿我不打算再介绍这种基于梯度的圆检测了。不放心大家,这里放上一个链接,大家自行查看:基于梯度的霍夫圆检测。
霍夫圆检测实战
这里先给出官网中对霍夫圆检测的介绍:HoughCircles()函数介绍。同样的我也会对这个函数进行一定的中文讲解。
- HoughCircles()函数🌸
void cv::HoughCircles( InputArray image,
OutputArray circles,int method,double dp,double minDist,double param1 =100,double param2 =100,int minRadius =0,int maxRadius =0)//InputArray image 输入的图像,必须是8位单通道图像。//OutputArray circles 返回检测到圆的信息,用一个向量保存这个向量编码为3或4个元素的浮点型向量(x,y, radius)或(x,y,radius,votes) ,x,y表示横纵坐标,radius表示圆的半径,votes表示投票数 //int method 检测的方法。目前可用的方法有HOUGH_GRADIENT和HOUGH_GRADIENT_ALT//double dp 图像分辨率与累加器分辨率之比。例如若dp=1, 则累加器与输入图片有相同的分辨率, 若dp=2,累加器的宽度和高度只有其一半//double minDist 被测圆中心之间的最小距离。如果该参数太小,可能会在检测出多个相交的圈。如果它太大,可能会漏掉一些圆。//double param1 = 100 第一个method-specific参数。对于HOUGH_GRADIENT和HOUGH_GRADIENT_ALT,它是传递给Canny边缘检测器的两者中较高的阈值(是较低的阈值的两倍)。注意,HOUGH_GRADIENT_ALT使用Scharr算法来计算图像导数,所以阈值通常应该较高,例如300或正常曝光和对比度图像。//double param2 = 100 第二个method-specific参数。对于HOUGH_GRADIENT,则为检测阶段圆中心的累加器阈值。它越小,可能检测到的假圆就越多。与较大累加器值相对应的圆将首先返回。在HOUGH_GRADIENT_ALT算法中,这是圆的“完美度”度量。越接近1,算法选择的圆的形状越好。在大多数情况下,0.9应该可以。如果你想更好地检测小圆,你可以将其降低到0.85,0.8或更少。。但同时也要限制搜索范围[minRadius, maxRadius],以避免许多错误的圆。//int minRadius = 0 需要检测圆的最小半径//int maxRadius = 0 需要检测圆的最大半径,如果该值等于0, 则使用图像的最大尺寸;如果小于0, 则返回圆心位置
下面给出C++的实现代码,这也是opencv官方给的,当然HoughCircles()函数部分你需要手动调剂一些参数以更好的完成检测任务。
#include"opencv2/imgcodecs.hpp"#include"opencv2/highgui.hpp"#include"opencv2/imgproc.hpp"usingnamespace cv;usingnamespace std;intmain(int argc,char** argv){constchar* filename = argc >=2? argv[1]:"E:\\毫米波雷达\\circle.jpg";// Loads an image
Mat src =imread(samples::findFile(filename), IMREAD_COLOR);// Check if image is loaded fineif(src.empty()){printf(" Error opening image\n");printf(" Program Arguments: [image_name -- default %s] \n", filename);return EXIT_FAILURE;}
Mat gray;cvtColor(src, gray, COLOR_BGR2GRAY);medianBlur(gray, gray,5);
vector<Vec3f> circles;HoughCircles(gray, circles, HOUGH_GRADIENT,1,80,// change this value to detect circles with different distances to each other100,20,1,0// change the last two parameters// (min_radius & max_radius) to detect larger circles);for(size_t i =0; i < circles.size(); i++){
Vec3i c = circles[i];
Point center =Point(c[0], c[1]);// circle centercircle(src, center,1,Scalar(0,0,100),2, LINE_AA);// circle outlineint radius = c[2];circle(src, center, radius,Scalar(100,0,0),2, LINE_AA);}imshow("detected circles", src);waitKey();return EXIT_SUCCESS;}
输出结果:可以看出检测的效果其实也并不是很好,当然很可能我调的参数不好,大家可以自行尝试。
呼呼呼~~🌻🌻🌻那么霍夫圆检测的原理和代码实战就讲到这里了,大家快去试试叭🥗🥗🥗
如若文章对你有所帮助,那就🛴🛴🛴
咻咻咻咻
duang点个赞呗
版权归原作者 秃头小苏 所有, 如有侵权,请联系我们删除。