Idea: Process the three RGB channels of the image separately, extract the black, then use Gaussian filtering to filter out the black shadows, and finally use Hough to detect the circle
// https://blog.csdn.net/piaoxuezhong/article/details/60757278?utm_medium=distribute.pc_relevant_bbs_down.none-task-blog-baidujs-1.nonecase&depth_1-utm_source=distribute.pc_relevant_bbs_down.none-task-blog-baidujs-1.nonecase
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include<iostream>
#include<opencv2/opencv.hpp>
#include<vector>
#include<algorithm>
#include<numeric>
#include<cmath>
#include<cassert>
using namespace cv;
using namespace std;
int main()
{
Mat srcImage = imread("31.jpg");
Mat midImage, dstImage;
namedWindow("原图", WINDOW_NORMAL);
imshow("原图", srcImage);
Mat BinRGBImg = srcImage.clone(); //用双重循环给此MAT赋值
unsigned char pixelB, pixelG, pixelR;
for (int i = 0; i < srcImage.rows; i++) //通过颜色分量将图片进行二值化处理
{
for (int j = 0; j < srcImage.cols; j++)
{
pixelB = srcImage.at<Vec3b>(i, j)[0]; //获取图片各个通道的值
pixelG = srcImage.at<Vec3b>(i, j)[1];
pixelR = srcImage.at<Vec3b>(i, j)[2];
// 用PS读取各像素点RGB通道值,可得知圆R、G、B范围
if (pixelB<95 && pixelB>45 && pixelR<70 && pixelR>45)
{
//将各个通道的值和各个通道阈值进行比较
BinRGBImg.at<Vec3b>(i, j)[0] = 255; //符合颜色阈值范围内的设置成白色
BinRGBImg.at<Vec3b>(i, j)[1] = 255;
BinRGBImg.at<Vec3b>(i, j)[2] = 255;
}
else
{
BinRGBImg.at<Vec3b>(i, j)[0] = 0; // 不符合颜色阈值范围内的设置为黑色
BinRGBImg.at<Vec3b>(i, j)[1] = 0;
BinRGBImg.at<Vec3b>(i, j)[2] = 0;
}
}
}
namedWindow("RGB通道处理后的图", WINDOW_NORMAL);
imshow("RGB通道处理后的图", BinRGBImg);
vector<Vec3f> circles;
cvtColor(BinRGBImg, BinRGBImg, CV_BGR2GRAY);
// 用高斯滤波滤去阴影部分的黑色,使得后续提取出来的圆为真正的圆
GaussianBlur(BinRGBImg, BinRGBImg, cv::Size(9, 9), 3, 3);
namedWindow("高斯滤波后", WINDOW_NORMAL);
imshow("高斯滤波后", BinRGBImg);
// BinRGBImg.rows/2为圆心之间的最小距离;40为检测圆的阈值,值越大检测出圆越难,但越精确
HoughCircles(BinRGBImg, circles, CV_HOUGH_GRADIENT, 1, BinRGBImg.rows / 2, 100, 40, 0, 0);
cout << "检测出圆的个数为" << circles.size() << endl;
//依次在图中绘制出圆
// 一般只能检测出一个圆,故这个for循环可以代替只输出一个圆
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(BinRGBImg, center, 3, Scalar(0, 255, 0), -1, 8, 0);
//绘制圆轮廓
circle(BinRGBImg, center, radius, Scalar(155, 50, 255), 3, 8, 0);
cout << "圆心为:" << center << endl;
cout << "半径为:" << radius << endl;
}
namedWindow("效果图", WINDOW_NORMAL);
imshow("效果图", BinRGBImg);
waitKey(0);
return 0;
}