图像轮廓的最小外接矩形和圆检测绘制

 

 

 

 

 

 

 

 代码:

 

#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()          逼近多边形曲线

 

posted @ 2019-09-19 21:49  量子与太极  阅读(890)  评论(0编辑  收藏  举报