函数原型
void 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位的单通道二进制图像。
- InputArray类型的circles,调用HoughCircles函数后存储了霍夫圆变换检测到的圆的输出矢量,每个矢量存储了3个元素的浮点矢量,分别是圆心的x和y以及半径r。
- int类型的method, 采用的检测方法,默认使用霍夫梯度法,即HOUGH_GRADIENT。
- double类型的dp,用来检测圆心的累加器图像的分辨率于输入图像之比的倒数,且此参数允许创建一个比输入图像分辨率低的累加器。例如,dp=1时,累加器和输入图像具有相同的分辨率;dp=2时,累加器便有输入图像一半的宽度和高度。
- double类型的minDist,霍夫变换检测到的圆的圆心之间的最小距离,即令算法能明显区分的两个不同圆之间的最小距离。这个参数如果太小的话,多个相邻的圆可能被错误地检测成一个重合的圆;反之,参数太大时,某些圆就不能检测出来。
- double类型的param1,默认值100。是检测方法对应的参数。对霍夫梯度法而言,表示传递给canny边缘检测算子的高阈值,而低阈值为高阈值的一半。
- double类型的param2,默认值100。是检测方法对应的参数。对霍夫梯度法而言,表示在检测阶段圆心的累加器阈值。它越小,就越可以检测到更多不存在的圆;反之,检测出的圆一般都很完美。
- int类型的minRadius,有默认值0,表示圆半径的最小值。
- int类型的maxRadius,有默认值0,表示圆半径的最大值。
什么是霍夫圆变换?
OpenCV支持霍夫圆变换,霍夫圆变换的基本原理和线变换大体上类似,只是点对应的二维极径极角空间被三维的圆心点x、y、r空间取代。说“大体上类似”,是因为如果完全用相同的方法的话,累加平面会被三维的累加容器所代替,在这三维中,一维是x,一维是y,另外一维是圆的半径r。这就意味着需要大量的内存并且执行效率会很低,速度会很慢。
对直线来说,一条直线能用参数极径和极角表示,而对圆来说,需要三个参数表示,通常采用一种叫霍夫梯度法的方法来解决圆变换的问题。
霍夫梯度法的原理
原理如下:
- 首先对图像应用边缘检测,如canny这类。
- 然后,对边缘图像的每一个非零点,采用局部梯度,即用Sobel()函数计算x和y方向的Sobel一阶导数得到梯度。
- 将梯度线上的每一个点都在累加器中累加。
- 以此类推,遍历边缘上每一个非0点。如果边缘上所有点的梯度线上的点都累加完,不难发现累加次数越多的点越有可能是圆心。
- 接下来对可能是圆心的每个中心进行分析,对单个中心而言,考虑所有的非0像素。
- 这些像素按照与该中心的距离排序。从到最大半径的最小距离算起,选非0像素最支持的一条半径。
- 如果一个中心收到边缘图像非0像素最充分的支持,并且到前期被选择的中心有足够的距离,那么它就会被保留下来。
这个实现可以使算法执行起来更高效,还能解决三维累加器中产生许多噪声并且使结果不稳定的稀疏分布问题。
测试代码
#include <iostream> #include <opencv2/opencv.hpp> using namespace std; using namespace cv; int main() { Mat src = imread("test.png"); Mat mid, dst; dst = src.clone(); cvtColor(src, mid, COLOR_BGR2GRAY); // 高斯滤波 GaussianBlur(mid, mid, Size(9, 9), 2, 2); // 霍夫梯度法实现圆检测 vector<Vec3f> circles; HoughCircles(mid, circles, HOUGH_GRADIENT, 1.5, 100, 200, 200, 0, 0); for (size_t i = 0; i < circles.size(); ++i) { Point center(cvRound(circles[i][0]), cvRound(circles[i][1])); int radius = cvRound(circles[i][2]); circle(dst, center, 3, Scalar(0, 255, 0), -1, 8, 0); circle(dst, center, radius, Scalar(0, 255, 255), 3, 8, 0); } imshow("src", src); imshow("result", dst); waitKey(0); return 0; }
测试效果
图1 原图
图2 圆检测效果
图3 不加限制的多重圆检测
该图是我之前做的一单私活中应用到的,当时的需求是进行圆检测,起初考虑用霍夫圆检测直接做,但是效果一般,并且准确性也不是很好;后面我基于边缘检测和特征圆识别方法,设计了一个识别圆的算法,虽然也不能解决所有的场景识别,但是效果比直接霍夫圆检测好一些,也更贴近圆的边缘,具体就不展示了。总的来说,霍夫圆检测还是不错的,针对一些简单些的图像还是能精准且稳定的识别,主要是应用很方便,调一个函数哈哈哈。
如果文章帮助到你了,可以点个赞让我知道,我会很快乐~加油!