# 整体设计流程
- 图像读取
- 灰度变换
- 高斯模糊
- Canny 边缘检测
- Hough 变换圆检测
- 输出圆心坐标与半径并在原图像画图
# 设计流程实现
# 图像读取和灰度变换
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 越大,模糊程度越高。实际我采用的高斯核大小是 ,x=13,y=0 的高斯核,其中 X 不变,高斯核大小改变,图像模糊程度几乎不变;高斯核大小改变,X 变大,图像模糊程度增高。
# 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 算子大小,默认 模板,L2gradient 判断图像梯度幅度是否计算正确,默认关闭。
图 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 使用的是霍夫梯度法。
使用 PS 的标尺工具粗略测到两个圆之间的距离为px, 大于这个范围则会检测不到圆 (图 2), 所以设 minDist 为 1100,HoughCircles 中 dp 默认为 1, 但实验中 dp=2 时才能检测出来,dp 为 1 精度太高检测不出 (图 1),dp 为 5 精度太低会检测多余的圆 (图 3)
# 输出圆心坐标与半径并在原图像画图
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):
完整源代码请戳此。
# 参考
Canny 边缘检测算法解析
Sobel 算子原理解析
找圆算法((HoughCircles) 总结与优化
标准霍夫线变换原理
霍夫变换:圆 — 介绍、用 Hough 检测圆、圆的 Hough 变换
霍夫变换
Hough Line Transform
Hough Circle Transform
OpenCV 霍夫梯度找圆算法