Goal
在本教程中,您将学习如何:
使用 OpenCV 函数 HoughCircles() 检测图像中的圆圈。
Theory
Hough Circle Transform
霍夫圆变换的工作方式与上一教程中解释的霍夫线变换大致相似。
在直线检测的情况下,一条直线由两个参数 (r,θ) 定义。 在圆形的情况下,我们需要三个参数来定义一个圆形:
其中 (xcenter,ycenter) 定义中心位置(绿点),r 是半径,它允许我们完全定义一个圆,如下所示:
为了提高效率,OpenCV 实现了一种比标准霍夫变换稍微复杂的检测方法:霍夫梯度法,它由两个主要阶段组成。 第一阶段涉及边缘检测并找到可能的圆心,第二阶段为每个候选圆找到最佳半径。 有关详细信息,请查看《学习 OpenCV》一书或您最喜欢的计算机视觉参考书目
For sake of efficiency, OpenCV implements a detection method slightly trickier than the standard Hough Transform: The Hough gradient method, which is made up of two main stages. The first stage involves edge detection and finding the possible circle centers and the second stage finds the best radius for each candidate center.
这个程序有什么作用?
加载图像并对其进行模糊以减少噪点
将霍夫圆变换应用于模糊图像。
在窗口中显示检测到的圆圈。
Code
我们将解释的示例代码可以从这里raw.githubusercontent.com下载。 可以在这里raw.githubusercontent.com 找到一个稍微漂亮的版本(显示用于更改阈值的滑动条)。
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
const char* filename = argc >=2 ? argv[1] : "smarties.png";
// Loads an image
Mat src = imread( samples::findFile( filename ), IMREAD_COLOR );
// Check if image is loaded fine
if(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,
gray.rows/16, // change this value to detect circles with different distances to each other
100, 30, 1, 30 // 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 center
circle( src, center, 1, Scalar(0,100,100), 3, LINE_AA);
// circle outline
int radius = c[2];
circle( src, center, radius, Scalar(255,0,255), 3, LINE_AA);
}
imshow("detected circles", src);
waitKey();
return EXIT_SUCCESS;
}
Explanation
我们使用的图像可以在这里raw.githubusercontent.com找到
Load an image:
const char* filename = argc >=2 ? argv[1] : "smarties.png";
// Loads an image
Mat src = imread( samples::findFile( filename ), IMREAD_COLOR );
// Check if image is loaded fine
if(src.empty()){
printf(" Error opening image\n");
printf(" Program Arguments: [image_name -- default %s] \n", filename);
return EXIT_FAILURE;
}
Convert it to grayscale:
Mat gray;
cvtColor(src, gray, COLOR_BGR2GRAY);
Apply a Median blur to reduce noise and avoid false circle detection:
应用中值滤波以减少噪声并避免错误的圆检测:
medianBlur(gray, gray, 5);
Proceed to apply Hough Circle Transform:
vector<Vec3f> circles; //检测到的圆
HoughCircles(gray, circles, HOUGH_GRADIENT, 1,
gray.rows/16, // 更改此值以检测彼此距离不同的圆圈
100, 30, 1, 30 // 更改最后两个参数
// (min_radius & max_radius) to detect larger circles
);
参数:
gray:输入图像(灰度)。
circles:一个向量,存储 3 个值的集合:每个检测到的圆的 xc,yc,r。
HOUGH_GRADIENT:定义检测方法。 目前这是 OpenCV 中唯一可用的。
dp = 1:分辨率的反比。
min_dist = gray.rows/16:检测到的中心之间的最小距离。
param_1 = 200:内部 Canny 边缘检测器的上限阈值。
param_2 = 100*:中心检测的阈值。
min_radius = 0:要检测的最小半径。 如果未知,则将零设为默认值。
max_radius = 0:要检测的最大半径。 如果未知,则将零设为默认值。
Draw the detected circles:
for( size_t i = 0; i < circles.size(); i++ )
{
Vec3i c = circles[i];
Point center = Point(c[0], c[1]);
// circle center
circle( src, center, 1, Scalar(0,100,100), 3, LINE_AA);
// circle outline
int radius = c[2];
circle( src, center, radius, Scalar(255,0,255), 3, LINE_AA);
}
您可以看到我们将在红色上绘制圆圈,在中心绘制一个小绿点
Display the detected circle(s) and wait for the user to exit the program:
显示检测到的圆圈并等待用户退出程序:
imshow("detected circles", src);
waitKey();
Result
使用测试图像运行上述代码的结果如下所示: