1. 程式人生 > >opencv求最小外接矩陣

opencv求最小外接矩陣

求最小外接矩陣的基本原理:

獲取點簇最開始的minx,maxx,miny,maxy確定最初的外接矩形,求外接矩形的面積,然後對點簇進行旋轉,按照下面公式即可:

旋轉之後,求出新的minx,maxx,miny,maxy,計算此時的面積,直到面積達到最小,對應的即為最小外接矩形。

關於影象旋轉參考:https://blog.csdn.net/zhouxuguang236/article/details/31820095

 

1.輸入是一幅圖,如邊緣圖(如canny邊緣檢測後,僅有0與255)

       測試程式碼:

        vector<vector<Point>> contours;
        vector<Vec4i> hierarchy;
        findContours(edge, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_NONE, Point());
        Mat imageContours = Mat::zeros(edge.size(), CV_8UC1);
        int idx, maxcontours = 0;
        vector<Point> selectpoint;
        for (int i = 0; i < contours.size(); i++)//有可能識別出幾組點簇分佈,取出最大的點簇
        {
            vector<Point> ptmp = contours[i];
            if (ptmp.size() > maxcontours)
            {
                selectpoint = ptmp;
                idx = i;
            }
        }

        //繪製輪廓
        drawContours(imageContours, contours, idx, Scalar(255), 1, 8, hierarchy);

        //繪製輪廓的最小外接矩形
        RotatedRect rect = minAreaRect(selectpoint);
        Point2f P[4];
        rect.points(P);//外接矩形的四個頂點
        for (int j = 0; j <= 3; j++)
        {
            line(imageContours, P[j], P[(j + 1) % 4], Scalar(255), 2);
        }
        imshow("MinAreaRect", imageContours);
        waitKey(0);

 

注意:

(1)部分關鍵量解釋

contours;//向量內每個元素儲存了一組由連續的Point點構成的點的集合的向量,每一組Point點集就是一個輪廓。
                   //有多少輪廓,向量contours就有多少元素
hierarchy;//向量內每一個元素包含了4個int型變數,向量hiararchy內的元素和輪廓向量contours內的元素是一一對應的,向量的容量相同。每一個元素的4個int型變數——hierarchy[i][0] ~hierarchy[i][3],分別表示第i個輪廓的後一個輪廓、前一個輪廓、父輪廓、內嵌輪廓的索引編號。如果當前輪廓沒有對應的後一個輪廓、前一個輪廓、父輪廓或內嵌輪廓的話,則hierarchy[i][0] ~hierarchy[i][3]的相應位被設定為預設值-1。

findContours(edge, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_NONE, Point());
//RETR_EXTERNAL,只檢測最外圍輪廓,包含在外圍輪廓內的內圍輪廓被忽略。
//CHAIN_APPROX_NONE,儲存物體邊界上所有連續的輪廓點到contours向量中。

(2)可能出現的問題

一般情況下,我們都期望找到包括影象所有邊緣的最小外接矩陣,但這種方法可能產生問題。如輸入影象如下圖:

其會分成兩組點簇:藍圈部分與紅圈部分。

取最大的點簇可能取不完整我們需要的矩形邊界,但可能外接矩陣沒問題,如下圖。但是點簇右下邊缺失,不利於後續操作,所以不推薦使用這種方法。

   

 

2.輸入是一組點(x,y)

測試程式碼:

        vector<Point> pointxy;
        vector<vector<Point>> aglcontours0;
        find_edge_coordinate(edge,pointxy);//提取邊緣部分,將影象中邊緣部分的點提取出來,並儲存
        aglcontours0.push_back(pointxy);
        Mat imageContours = Mat::zeros(edge.size(), CV_8UC1);
        drawContours(imageContours, aglcontours0, 0, Scalar(255), 1, 8);

        RotatedRect rect = minAreaRect(pointxy);//查詢最小外接矩形
        Point2f P[4];
        rect.points(P);//外接矩形的四個頂點
        for (int j = 0; j <= 3; j++)
        {
            line(imageContours, P[j], P[(j + 1) % 4], Scalar(128), 2);
        }
        imshow("MinAreaRect", imageContours);
        waitKey(0);

輸出顯示:

說明:不知道為啥中間部分也成了白色的。。。。。。