最近跟着老师做项目,需要对图片中拍摄的圆形标志点进行检测和提取,查了一些资料和博客,记录一下过程。实际拍摄的图片如图所示:
图片处理过程的大概思路是:
1、进行双边滤波处理(可以较好的保留圆形标志的边缘信息)
CV_EXPORTS_W void bilateralFilter( InputArray src, OutputArray dst, int d,
double sigmaColor, double sigmaSpace,
int borderType = BORDER_DEFAULT );
2、利用Mean shift区域分割算法分割圆形标志(分割次数可以根据图片具体情况而定)
CV_EXPORTS_W void pyrMeanShiftFiltering( InputArray src, OutputArray dst,
double sp, double sr, int maxLevel = 1,
TermCriteria termcrit=TermCriteria(TermCriteria::MAX_ITER+TermCriteria::EPS,5,1) );
double sp—滑动空间的窗口半径
double sr—颜色窗口半径
termcrit:迭代算法终止条件(可以选择迭代次数或者迭代精度作为终止条件)
3、将分割出圆形标志进行Canny算子边缘检测
4、利用findContours函数获取轮廓信息并填充区域轮廓内部
findContours函数的定义:
CV_EXPORTS_W void findContours( InputArray image, OutputArrayOfArrays contours,
OutputArray hierarchy, int mode,
int method, Point offset = Point());
Mat draw00 = Mat(resultCanny.size(), CV_8UC3, Scalar(255, 255, 255));
findContours(resultCanny, Contours, Hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));//轮廓检测
for (int i = 0; i < Contours.size(); i++)
{
//Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
drawContours(draw00, Contours, i, (0, 0, 0), -1, 8, Hierarchy, 0, Point());//填充内部区域
//circle(drawing_0, mc[i], 4, color, -1, 8, 0);
}
6、再次使用轮廓提取函数findContours获取轮廓信息并计算轮廓矩和提取轮廓质心
findContours(dst_2, Contours, Hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));//轮廓检测
vector<Moments> mu(Contours.size());
vector<Point2f> mc(Contours.size());
for (int i = 0; i < Contours.size(); i++) {
mu[i] = moments(Contours[i], false);
}
for (int i = 0; i < Contours.size(); i++)
{
mc[i] = Point2f(mu[i].m10 / mu[i].m00, mu[i].m01 / mu[i].m00);//质心计算
}
Mat src1 = imread("E:/标志检测/image/2/DMcameraTest-Snapshot-20161101081515-560083999222.BMP");
Mat dst = src1.clone();//原图像深拷贝到目标图像
Mat src2 = src1.clone();
Mat blur_deal;
int ksizes = 5;
//medianBlur(src1, blur_deal, ksizes);//中值滤波处理
bilateralFilter(src1, blur_deal,10,50,50);//双边滤波
Mat result1, result2;
TermCriteria T10 = TermCriteria(TermCriteria::COUNT | TermCriteria::EPS, 10, 0.1);
pyrMeanShiftFiltering(blur_deal, result1, 5, 25, 2, T10);
pyrMeanShiftFiltering(result1, result2, 5, 25, 2, T10);
//pyrMeanShiftFiltering(result2, result2, 5, 25, 2, T10);
namedWindow("分割结果", WINDOW_AUTOSIZE);
imshow("分割结果", result1);
//对图像进行Canny边缘检测
Mat imgCanny, resultCanny;
Canny(src1, imgCanny, 50, 100);
Canny(result2, resultCanny,50,100);
vector<vector<Point>> Contours;
vector<Vec4i> Hierarchy;
vector<Vec3f> circles;
Mat gray_src;
cvtColor(result2, gray_src, COLOR_BGR2GRAY);//转为灰度图像
Mat draw00 = Mat(resultCanny.size(), CV_8UC3, Scalar(255,255,255));
findContours(resultCanny, Contours, Hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));//轮廓检测
for (int i = 0; i < Contours.size(); i++)
{
drawContours(draw00, Contours, i, (0,0,0), -1, 8, Hierarchy, 0, Point());
}
Mat test00;
cvtColor(draw00, test00,COLOR_BGR2GRAY);
threshold(test00, test00, 100, 255, THRESH_BINARY_INV);//二值化
findContours(test00, Contours, Hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));//轮廓检测
vector<Moments> mu(Contours.size());
vector<Point2f> mc(Contours.size());
for (int i = 0; i < Contours.size(); i++) {
mu[i] = moments(Contours[i], false);
}
for (int i = 0; i < Contours.size(); i++) {
cout << "mu[].m10: " << mu[i].m10 << " mu[].m00: " << mu[i].m00 << " mu[].m01: " << mu[i].m01 << endl;
cout << "轮廓大小:" << contourArea(Contours[i]) << endl;
mc[i] = Point2f(mu[i].m10 / mu[i].m00, mu[i].m01 / mu[i].m00);//质心计算
waitKey(0);
return 0;
}