图像轮廓的最小外接矩形和圆检测绘制
代码:
#include <opencv2/opencv.hpp> #include <iostream> #include <math.h> using namespace std; using namespace cv; Mat src, gray_src, drawImg; int threshold_v = 170; //阈值二值化的初始值为170 int threshold_max = 255; //最大值为255 const char* output_win = "rectangle-demo"; RNG rng(12345); void Contours_Callback(int, void*); int main(int argc, char** argv) { src = imread("L:/13.jpg"); if (!src.data) { printf("could not load image...\n"); return -1; } cvtColor(src, gray_src, CV_BGR2GRAY); blur(gray_src, gray_src, Size(3, 3), Point(-1, -1)); const char* source_win = "input image"; namedWindow(source_win, CV_WINDOW_AUTOSIZE); namedWindow(output_win, CV_WINDOW_AUTOSIZE); imshow(source_win, src); createTrackbar("Threshold Value:", output_win, &threshold_v, threshold_max, Contours_Callback); //创建阈值拖动窗口,回调Contours_Callback函数 Contours_Callback(0, 0); waitKey(0); return 0; } void Contours_Callback(int, void*) { Mat binary_output; //定义一个二值化的输出矩阵 vector<vector<Point>> contours; //point点集的二维数组,数组的个数和每个数的长度都是可变 vector<Vec4i> hierachy; //4i四维的整数,个数可变 threshold(gray_src, binary_output, threshold_v, threshold_max, THRESH_BINARY); //二值化 imshow("binary image", binary_output); findContours(binary_output, contours, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(-1, -1));//找出轮廓 vector<vector<Point>> contours_ploy(contours.size()); //定义一个输出轮廓的点集,与contours一样的 vector<Rect> ploy_rects(contours.size()); // vector<Point2f> ccs(contours.size()); //圆心 vector<float> radius(contours.size()); //半径 vector<RotatedRect> minRects(contours.size()); //定义最小旋转矩形数组 vector<RotatedRect> myellipse(contours.size()); //定义最小圆数组 for (size_t i = 0; i < contours.size(); i++) { approxPolyDP(Mat(contours[i]), contours_ploy[i], 3, true); //多边形拟合:approxPolyDP函数参数:1.图像轮廓点集 2.输出多边形点集 3.两个轮廓之间最大距离 4.是否为封闭图形 ploy_rects[i] = boundingRect(contours_ploy[i]); //boundingRect函数:计算出轮廓的垂直边界最小矩形赋给ploy_rects[i] minEnclosingCircle(contours_ploy[i], ccs[i], radius[i]); //minEnclosingCircle函数参数:1.输入点集 2.输出圆心坐标 3.输出圆半径 if (contours_ploy[i].size() > 5) { //绘制图形时边界不能低于5个像素 myellipse[i] = fitEllipse(contours_ploy[i]); minRects[i] = minAreaRect(contours_ploy[i]); } } // draw it drawImg = Mat::zeros(src.size(), src.type()); //定义一个src大小和类型的矩阵给drawImg Point2f pts[4]; //定义一维数组分别为每个矩形的四个点 for (size_t t = 0; t < contours.size(); t++) { Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)); //颜色取随机 //rectangle(drawImg, ploy_rects[t], color, 2, 8); //circle(drawImg, ccs[t], radius[t], color, 2, 8); if (contours_ploy[t].size() > 5) { ellipse(drawImg, myellipse[t], color, 1, 8); minRects[t].points(pts); for (int r = 0; r < 4; r++) { line(drawImg, pts[r], pts[(r + 1) % 4], color, 1, 8); //找每个矩形的四个点连线,第四个点过界取模4运算回到pts[0] } } } imshow(output_win, drawImg); return; }
结果:
OpenCV提取轮廓之后,还可以进行许多操作:
ArcLength() 计算轮廓长度
ContourArea() 计算轮廓区域的面积
BoundingRect() 轮廓的外包矩形
ConvexHull() 提取轮廓的凸包
IsContourConvex() 测试轮廓的凸性
MinAreaRect() 轮廓的最小外包矩形
MinEnclosingCircle() 轮廓的最小外包圆
fitEllipse() 用椭圆拟合二维点集
approxPolyDP() 逼近多边形曲线