经过多次试验,发现利用OpenCV的霍夫圆变换查找出来的圆,其圆心位置并不准确,而且参数调节较为麻烦。于是想到利用轮廓查找的方式来进行圆检测,我们可以通过判断轮廓的外接矩形的横纵比来判断该轮廓是否为圆形。一般而言,圆的外接矩形肯定近似于一个正方形,因此宽高比接近1.0 。总体思路如下:阈值分割->形态学/滤波降噪->轮廓查找->范围过滤->圆形拟合。代码如下,仅供参考。
int MinR = 100; int MaxR = 300;
Mat src_img, binary_img, dst_img;
src_img = imread("test.bmp", IMREAD_GRAYSCALE);//灰度图读入
threshold(src_img, binary_img, 158, 255, THRESH_BINARY );
imshow("trs", binary_img);
//imwrite("trs.bmp", binary_img);
//可以根据实际需求选择使用的滤波进行降噪
//GaussianBlur(binary_img, binary_img, Size(3, 3), 0, 0);
//boxFilter(binary_img, binary_img,-1, Size(3, 3));
//blur(binary_img, binary_img, Size(3, 3));
vector> contours;
vector hireachy;
// 形态学操作
Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
// 构建形态学操作的结构元
morphologyEx(binary_img, binary_img, MORPH_CLOSE, kernel, Point(-1, -1));
//闭操作
kernel = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
// 构建形态学操作的结构元
morphologyEx(binary_img, binary_img, MORPH_OPEN, kernel, Point(-1, -1));
//开操作
//imshow("开操作", dst_img);
findContours(binary_img, contours, hireachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point());
imshow("bf", binary_img);
//imwrite("bf.bmp", binary_img);
Mat result_img = src_img.clone();
cvtColor(result_img, result_img, COLOR_GRAY2BGR);
//灰度图转为彩色图
for (int i = 0; i < hireachy.size(); i++)
{
// drawContours(src_img, contours, i, Scalar(0, 0, 255), -1, 8, Mat(), 0, Point());
if (contours[i].size() < 5)continue;
double area = contourArea(contours[i]);
if (area < 2000)continue;
//晒选出轮廓面积大于2000的轮廓
double arc_length = arcLength(contours[i], true);
double radius = arc_length / (2 * PI);
if (!(MinR < radius && radius < MaxR))
{
continue;
}
RotatedRect rect = fitEllipse(contours[i]);
float ratio = float(rect.size.width) / float(rect.size.width);
if (ratio < 1.1 && ratio > 0.9)
//因为圆的外接直立矩形肯定近似于一个正方形,因此宽高比接近1.0
{
printf("X: %f\n", rect.center.x);
printf("Y: %f\n", rect.center.y);
printf("圆的面积: %f\n", area);
printf("圆的半径: %f\n", radius);
ellipse(result_img, rect, Scalar(0,255, 255),2);
circle(result_img, rect.center, 2, Scalar(0,255,0), 2, 8, 0);
}
}
imshow("dst", result_img);
imwrite("dst.bmp", result_img);
waitKey();
测试图如下:
算法检测出的圆形较为准确,且参数易调。主要根据调节阈值筛选轮廓,也可以采用自适应阈值。根据用户的需求进行半径与圆面积的筛选,最后得到想要的圆。如有不足,还请指正。转载请标明出处。希望能对各位有所帮助。