目录
1 概念讲解及用处
圆检测是计算机视觉领域中的一项重要任务,它用于在图像或视频中检测和定位圆形对象。在很多应用中,圆检测可以用来识别或跟踪物体,例如工业自动化、目标识别、机器人导航等。
霍夫圆检测(Hough Circle Detection)是一种图像处理算法,用于在给定图像中检测和定位圆形目标。它是基于霍夫变换的扩展,通过在参数空间中进行累加来寻找圆形轮廓。
霍夫圆检测的核心思想是将圆形表示为参数空间中的一个曲线,并通过累加器数组来记录曲线与图像中边缘点的交叉情况。当某个参数组合的累加值超过预设阈值时,就认为该参数组合对应的圆存在于图像中。
2 霍夫圆检测原理
我们都知道在直角坐标系中,对于圆我们可以用解析式来表示。
其中,a是圆心的x坐标,b是圆心的y坐标,R是圆的半径;
现在我们假设圆上的三点A(x0,y0)、B(x1,y1),c(x2,y2)。 根据直角坐标与极坐标的转换关系:
由此我们可以得到关于a,b和R的表达式:
由此我们可以得出: 直角坐标系中圆上的三个点,在极坐标中也是三个点,但是以这三个点为圆心,以R为半径,这三个圆将交于一点,该点就是要检测的圆的圆心点。
进而更近一步,直角坐标系中圆上任意个点(>3),在极坐标中,以这些点为圆心,以半径R画圆,这些圆将交于一点,该点就是要检测的圆的圆心点。
3 霍夫直线检测步骤
具体来说,霍夫圆检测的步骤如下:
-
边缘检测:首先,需要对输入图像进行边缘检测,以便找到潜在的圆形轮廓。常用的边缘检测算法包括Canny边缘检测。
-
参数空间定义:在霍夫圆检测中,使用三个参数来表示圆形:圆心坐标
(a, b)
和半径r
。为了确定这些参数的范围,需要定义一个参数空间,通常可以根据图像大小和目标尺寸进行设置。 -
累加器初始化:创建一个累加器数组,大小与参数空间相匹配,并初始化为零。
-
参数空间遍历:对于每个边缘点,计算其对应的圆心坐标和半径,并在累加器数组中对应位置进行累加。这一步骤需要遍历参数空间中所有可能的参数组合。
-
阈值检测:当累加器数组中某个位置的累加值超过设定的阈值时,认为对应的圆存在于图像中。
-
圆形细化:为了提高检测结果的准确性,可以进行圆形细化操作,例如非最大抑制,以消除重叠或相似的圆。
-
输出结果:最后,将检测到的圆形轮廓输出或在原始图像上进行绘制,以便可视化或进一步处理。
4 API详解
OpenCV提供了函数来实现圆检测,其中最常用的是HoughCircles函数。以下是HoughCircles函数的详细介绍:
void HoughCircles( InputArray image, OutputArray circles, int method,
double dp, double minDist, double param1 = 100, double param2 = 100,
int minRadius = 0, int maxRadius = 0 );
参数说明:
image:输入的单通道灰度图像。
circles:输出参数,包含检测到的圆的圆心坐标和半径。
method:定义霍夫变换方法,一般使用CV_HOUGH_GRADIENT。
dp:候选圆心之间的累加器分辨率的倒数。dp越小,累加器数组的尺寸越大。
minDist:检测到的圆之间的最小距离。如果设置为负值,则函数会自动根据图像尺寸计算最小距离。
param1:第一个阈值用于边缘检测。默认值为100。
param2:第二个阈值用于确定圆心的累加器阈值。默认值为100。
minRadius:检测到的圆的最小半径。默认值为0。
maxRadius:检测到的圆的最大半径。默认值为0,表示没有限制。
HoughCircles函数基于霍夫变换的原理,通过在参数空间中进行累加来寻找圆形轮廓。它会返回一个包含所有检测到的圆的矢量,每个圆由三个值表示:圆心坐标 (x, y) 和半径 r。
使用HoughCircles函数时,可以根据具体需求调整参数,例如设置适当的阈值、最小距离和半径范围,以获得更准确的圆检测结果。
5 用C++编写代码进行实现
下面是使用OpenCV和C++实现圆检测的示例代码:
#include <opencv2/opencv.hpp>
int main()
{
cv::Mat image = cv::imread("image.jpg", cv::IMREAD_GRAYSCALE);
cv::GaussianBlur(image, image, cv::Size(5, 5), 2, 2); // 对图像进行高斯模糊
std::vector<cv::Vec3f> circles;
cv::HoughCircles(image, circles, cv::HOUGH_GRADIENT, 1, image.rows / 8, 200, 100, 0, 0);
for (size_t i = 0; i < circles.size(); i++)
{
cv::Vec3i c = circles[i];
cv::Point center = cv::Point(c[0], c[1]);
int radius = c[2];
// 在图像上绘制检测到的圆
cv::circle(image, center, radius, cv::Scalar(0, 255, 0), 2);
}
cv::imshow("Circle Detection", image);
cv::waitKey(0);
return 0;
}