# 整体设计流程

  1. 图像读取
  2. 灰度变换
  3. 高斯模糊
  4. Canny 边缘检测
  5. Hough 变换圆检测
  6. 输出圆心坐标与半径并在原图像画图

# 设计流程实现

# 图像读取和灰度变换

Mat imread(const String& filename, int flags);
// Mat image, image1;// 一个基本的图像容器
// image = imread("G:/Storage/Code/Graphics/CoinDetection/1.5.jpg", IMREAD_GRAYSCALE);//2.png 1.jpg
// image1 = imread("G:/Storage/Code/Graphics/CoinDetection/1.5.jpg");

imread 函数返回一个包含图像信息的矩阵,flags 是文件读取的方式,默认三通道彩色图像读取,IMREAD_GRAYSCALE 是将图像读取为单通道灰度图像。

原图
灰度变换

# 高斯模糊

void GaussianBlur(InputArray src,OutputArray dst,
                 Size ksize,double sigmaX, double sigmaY
                ,int borderType)
// Mat imageBlur;
// GaussianBlur (image, imageBlur, Size (13,13),2);// 高斯模糊

dst 是输出,ksize 为高斯内核大小,sigmaX 和 sigmaY 分别是 XY 方向的滤波系数。ksize (x,y) 大小与模糊程度无关,sigmaX 自定义,sigmaY 默认为 0,sigmaX 越大,模糊程度越高。实际我采用的高斯核大小是5×55\times5 ,x=13,y=0 的高斯核,其中 X 不变,高斯核大小改变,图像模糊程度几乎不变;高斯核大小改变,X 变大,图像模糊程度增高。

size(13,13) X=13 Y=0
size(13,13) X=2 Y=0
size(31,31) X=2 Y=0

# Canny 边缘检测

void Canny( InputArray image, OutputArray edges
        ,double threshold1, double threshold2,
        int apertureSize, bool L2gradient )
// Mat imageCanny;
// Canny (imageBlur, imageCanny, 50,143);//canny 边缘检测

threshold1 和 threshold2 分别是低高双阈值,范围设在 1:2 到 1:3 之间最好,apertureSize 表示 sobel 算子大小,默认3×33\times 3 模板,L2gradient 判断图像梯度幅度是否计算正确,默认关闭。

t1=50,t2=60
t1=50,t2=143
t1=50,t2=200

图 3 的 threshold1:threshold2 大于 1:3, 边缘细节不够,连续性不强,图 1 的 threshold1:threshold2 小于 1:2, 无关细节太多,对后面霍夫变换检测要求更大的计算量,所以实际采用的是 threshold1=50,threshold2=143 的图 2。

# Hough 变换圆检测

void HoughCircles( InputArray image, OutputArray circles,
                  int method, double dp, double minDist,
                  double param1, double param2,int minRadius, int maxRadius)
// vector<Vec3f> circles;
// HoughCircles (imageCanny, circles, HOUGH_GRADIENT, 1, 1100);//hough 变换圆检测

circles 为输出,是一个类数组,包含圆心坐标和半径。minDist 是检测到的圆的中心之间的最小距离,如果设定过大,会导致检测不到圆。dp 是累加器分辨率与图像分辨率的反比,默认为 1。param1 和 param2 双阈值和圆心阈值,避免检测错误的圆圈,默认为 100。minRadius 和 maxRadius 是限定检测圆的最小和最大圆半径,默认为 0。method 是圆检测方法,现有 HOUGH_GRADIENT 和 HOUGH_GRADIENT_ALT, 其中 HOUGH_GRADIENT 使用的是霍夫梯度法。

dp=1,minDist=1100
dp=2,minDist=1300
dp=5,minDist=1100

使用 PS 的标尺工具粗略测到两个圆之间的距离为120713661207\sim 1366px, 大于这个范围则会检测不到圆 (图 2), 所以设 minDist 为 1100,HoughCircles 中 dp 默认为 1, 但实验中 dp=2 时才能检测出来,dp 为 1 精度太高检测不出 (图 1),dp 为 5 精度太低会检测多余的圆 (图 3)
dp=2,minDist=1100

# 输出圆心坐标与半径并在原图像画图

cout << "单位:pixel" << endl;
for (size_t i = 0; i < circles.size(); i++)// 输出圆心与半径
{
    cout << "圆心为(" << circles[i][0] << "," << circles[i][1] << ")" << "半径为" << circles[i][2] << endl;//
}
Mat display = image1.clone();// 画出圆所在的范围
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 center
    circle(display, center, 3, Scalar(0, 255, 0), -1, 8, 0);
    // circle outline
    circle(display, center, radius, Scalar(0, 0, 255), 3, 8, 0);
}

在 PS 粗略测到的五个圆坐标和半径为 (单位为 px):

(1496,1508) 404
(2000,444) 378
(508,2580) 380
(1496,1508) 400.90
(728,552) 385.27
最终得出的结果和我实际测到的结果有偏差,但在可接受范围内。

完整源代码请戳此

# 参考

Canny 边缘检测算法解析
Sobel 算子原理解析
找圆算法((HoughCircles) 总结与优化
标准霍夫线变换原理
霍夫变换:圆 — 介绍、用 Hough 检测圆、圆的 Hough 变换
霍夫变换
Hough Line Transform
Hough Circle Transform
OpenCV 霍夫梯度找圆算法

更新于 阅读次数

请我喝[茶]~( ̄▽ ̄)~*

Jelly27th 微信支付

微信支付

Jelly27th 支付宝

支付宝