OpenCV-霍夫圆变换cv::HoughCircles

作者:翟天保Steven
版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处 

函数原型

void HoughCircles( InputArray image, OutputArray circles,
                   int method, double dp, double minDist,
                   double param1 = 100, double param2 = 100,
                   int minRadius = 0, int maxRadius = 0 );

参数说明

  1. InputArray类型的image,输入(input)图像,需为8位的单通道二进制图像。
  2. InputArray类型的circles,调用HoughCircles函数后存储了霍夫圆变换目标检测到的圆的输出矢量,每个矢量存储了3个元素的浮点矢量,分别是圆心的x和y以及半径r。
  3. int类型的method, 采用的目标检测方法,默认使用霍夫梯度(gradient)法,即HOUGH_GRADIENT。
  4. double类型的dp,用来目标检测圆心的累加器图像的分辨率于输入(input)图像之比的倒数,且此参数允许创建一个比输入(input)图像分辨率低的累加器。例如,dp=1时,累加器和输入(input)图像具有相同的分辨率;dp=2时,累加器便有输入(input)图像一半的宽度和高度。
  5. double类型的minDist,霍夫变换目标检测到的圆的圆心之间的最小距离,即令算法能明显区分的两个不同圆之间的最小距离。这个参数如果太小的话,多个相邻的圆可能被错误地目标检测成一个重合的圆;反之,参数太大时,某些圆就不能目标检测出来。
  6. double类型的param1,默认值100。是目标检测方法对应的参数。对霍夫梯度(gradient)法而言,表示传递给canny边缘目标检测算子的高阈值(Threshold),而低阈值(Threshold)为高阈值(Threshold)的一半。
  7. double类型的param2,默认值100。是目标检测方法对应的参数。对霍夫梯度(gradient)法而言,表示在目标检测阶段圆心的累加器阈值(Threshold)。它越小,就越可以目标检测到更多不存在的圆;反之,目标检测出的圆一般都很完美。
  8. int类型的minRadius,有默认值0,表示圆半径的最小值。
  9. int类型的maxRadius,有默认值0,表示圆半径的最大值。

什么是霍夫圆变换?

       OpenCV支持霍夫圆变换,霍夫圆变换的基本原理和线变换大体上类似,只是点对应的二维极径极角空间被三维的圆心点x、y、r空间取代。说“大体上类似”,是因为如果完全用相同的方法的话,累加平面会被三维的累加容器所代替,在这三维中,一维是x,一维是y,另外一维是圆的半径r。这就意味着需要大量的内存并且执行效率会很低,速度会很慢。

       对直线来说,一条直线能用参数极径和极角表示,而对圆来说,需要三个参数表示,通常采用一种叫霍夫梯度(gradient)法的方法来解决圆变换的问题。

霍夫梯度(gradient)法的原理

       原理如下:

  1. 首先对图像应用边缘目标检测,如canny这类。
  2. 然后,对边缘图像的每一个非零点,采用局部梯度(gradient),即用Sobel()函数计算x和y方向的Sobel一阶导数得到梯度(gradient)。
  3. 将梯度(gradient)线上的每一个点都在累加器中累加。
  4. 以此类推,遍历边缘上每一个非0点。如果边缘上所有点的梯度(gradient)线上的点都累加完,不难发现累加次数越多的点越有可能是圆心。
  5. 接下来对可能是圆心的每个中心进行分析,对单个中心而言,考虑所有的非0像素。
  6. 这些像素按照与该中心的距离排序。从到最大半径的最小距离算起,选非0像素最支持的一条半径。
  7. 如果一个中心收到边缘图像非0像素最充分的支持,并且到前期被选择的中心有足够的距离,那么它就会被保留下来。

       这个实现可以使算法执行起来更高效,还能解决三维累加器中产生许多噪声并且使结果不稳定的稀疏分布(Distribution)问题。

测试代码

#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);
	// 高斯(RBM Gaussian RBM)滤波
	GaussianBlur(mid, mid, Size(9, 9), 2, 2);
	// 霍夫梯度(gradient)法实现圆目标检测
	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;
}

测试效果

OpenCV-霍夫圆变换cv::HoughCircles
图1 原图
OpenCV-霍夫圆变换cv::HoughCircles
图2 圆目标检测效果
OpenCV-霍夫圆变换cv::HoughCircles
图3 不加限制的多重圆目标检测

       该图是我之前做的一单私活中应用到的,当时的需求是进行圆目标检测,起初考虑用霍夫圆目标检测直接做,但是效果一般,并且准确性也不是很好;后面我基于边缘目标检测和特征圆识别方法,设计了一个识别圆的算法,虽然也不能解决所有的场景识别,但是效果比直接霍夫圆目标检测好一些,也更贴近圆的边缘,具体就不展示了。总的来说,霍夫圆目标检测还是不错的,针对一些简单些的图像还是能精准且稳定的识别,主要是应用很方便,调一个函数哈哈哈。

       如果文章帮助到你了,可以点个赞让我知道,我会很快乐~加油!

版权声明:本文为博主翟天保Steven原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/zhaitianbao/article/details/121399426

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
xiaoxingxing的头像xiaoxingxing管理团队
上一篇 2021年11月22日 下午8:34
下一篇 2021年11月22日 下午9:04

相关推荐