现在我们想从一个杂乱的背景中提取出某个规则图像的轮廓,比方说圆。我们如何才能在一张图像中找的圆的轮廓,同时找到它的圆心坐标以及它的面积和周长呢?我的思路是阈值分割+形态学处理+高宽比过滤。大家也可以尝试下霍夫圆检测的思路。
接下我们编写代码:
#include <opencv2/opencv.hpp> #include <iostream> #include <math.h> using namespace cv; using namespace std; Mat src_img, binary_img, dst_img; int main() { src_img = imread("2018.4.26.png", IMREAD_GRAYSCALE); //灰度读取,在读入图像的同时进行色彩转换,这可以提高运行速度并减少内存的使用 if (src_img.empty()) { printf("could not load the image...\n"); return -1; } namedWindow("原图", CV_WINDOW_AUTOSIZE); imshow("原图", src_img); // 图像二值化 threshold(src_img, binary_img, 0, 255, THRESH_BINARY | THRESH_OTSU); imshow("二值图像", binary_img); // 形态学操作 Mat kernel = getStructuringElement(MORPH_RECT, Size(5, 5), Point(-1, -1)); // 构建形态学操作的结构元 morphologyEx(binary_img, dst_img, MORPH_CLOSE, kernel, Point(-1, -1)); //闭操作 imshow("闭操作", dst_img); kernel = getStructuringElement(MORPH_RECT, Size(5,5), Point(-1, -1)); // 构建形态学操作的结构元 morphologyEx(dst_img, dst_img, MORPH_OPEN, kernel, Point(-1, -1)); //开操作 imshow("开操作", dst_img); // 寻找轮廓 vector<vector<Point>> contours; vector<Vec4i> hireachy; findContours(dst_img, contours, hireachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point()); Mat result_img = Mat::zeros(src_img.size(), CV_8UC3); // 创建与原图同大小的黑色背景 Point circle_center; //定义圆心坐标 for (auto t = 0; t < contours.size(); ++t) { // 面积过滤 double area = contourArea(contours[t]); //计算点集所围区域的面积 if (area < 100) //晒选出轮廓面积大于100的轮廓 continue; // 横纵比过滤 Rect rect = boundingRect(contours[t]); // 求点集的最小直立外包矩形 float ratio = float(rect.width) / float(rect.height); //求出宽高比 if (ratio < 1.1 && ratio > 0.9) //因为圆的外接直立矩形肯定近似于一个正方形,因此宽高比接近1.0 { drawContours(result_img, contours, t, Scalar(0, 0, 255), -1, 8, Mat(), 0, Point()); ////在黑色背景图上画出圆,注意其中参数-1的意义 printf("圆的面积: %f\n", area); double arc_length = arcLength(contours[t], true); //计算点集所围区域的周长 printf("圆的周长 : %f\n", arc_length); int x = rect.x + rect.width / 2; int y = rect.y + rect.height / 2; circle_center = Point(x, y); //得到圆心坐标 cout << "圆心坐标:" << "宽"<<circle_center.x<<" "<<"高"<< circle_center.y << endl; circle(result_img, circle_center, 2, Scalar(0, 255, 255), 2, 8, 0); } } imshow("结果", result_img); Mat circle_img = src_img.clone(); cvtColor(circle_img, circle_img, COLOR_GRAY2BGR); //灰度图转化为彩色图 circle(circle_img, circle_center, 2, Scalar(0, 0, 255), 2, 8, 0); //在原图上画出圆心 imshow("最终结果", circle_img); waitKey(0); return 0; }
运行程序,如下:
显然结果很准确!