opencv輪廓外接矩形


1.尋找輪廓

api

 void cv::findContours( InputOutputArray image, OutputArrayOfArrays contours, OutputArray hierarchy, int mode, int method, Point offset = Point() 

各個參數詳解如下:

  • Image表示輸入圖像,必須是二值圖像,二值圖像可以threshold輸出、Canny輸出、inRange輸出、自適應閾值輸出等。
  • Contours獲取的輪廓,每個輪廓是一系列的點集合
  • Hierarchy輪廓的層次信息,每個輪廓有四個相關信息,分別是同層下一個、前一個、第一個子節點、父節點
  • mode 表示輪廓尋找時候的拓撲結構返回 -RETR_EXTERNAL表示只返回最外層輪廓 -RETR_TREE表示返回輪廓樹結構
    • CV_RETR_EXTERNAL:只檢測外輪廓。忽略輪廓內部的洞

    • CV_RETR_LIST:檢測所有輪廓,但不建立繼承(包含)關系

    • CV_RETR_TREE:檢測所有輪廓,並且建立所有的繼承(包含)關系。也就是說用CV_RETR_EXTERNAL和CV_RETR_LIST方法的時候hierarchy這個變量是沒用的,因為前者沒有包含關系,找到的都是外輪廓,后者僅僅是找到所喲的輪廓但並不把包含關系區分。用TREE這種檢測方法的時候我們的hierarchy這個參數才是有意義的

    • CV_RETR_CCOMP:檢測所有輪廓,但是僅僅建立兩層包含關系。外輪廓放到頂層,外輪廓包含的第一層內輪廓放到底層,如果內輪廓還包含輪廓,那就把這些內輪廓放到頂層去。

  • Method表示輪廓點集合取得是基於什么算法,常見的是基於CHAIN_APPROX_SIMPLE鏈式編碼方法

注意,如果圖像底色是白色,則檢測最外層的輪廓為圖像邊框

 

2.繪制輪廓外接矩形

繪制外接矩形包括兩種:

  • 繪制最大外接矩形
(Rect cv::boundingRect( InputArray points ))

其中,輸入參數points為一系列點的集合(findContours中contours中的一個元素),對輪廓來說就是該輪廓的點集 返回結果是一個矩形,x, y, w, h

  • 繪制最小外接矩形
RotatedRect cv::minAreaRect( InputArray points )

 

其中,輸入參數points為一系列點的集合(findContours中contours中的一個元素) ,對輪廓來說就是該輪廓的點集 返回結果是一個旋轉矩形,包含下面的信息: - 矩形中心位置 - 矩形的寬高 - 旋轉角度。

 

3.代碼

EdgeDetection.h

 1 #pragma once
 2 #include<opencv2/opencv.hpp>
 3 #include<iostream>
 4 
 5 using namespace std;
 6 using namespace cv;
 7 
 8 
 9 class EdgeDetection
10 {
11     cv::Mat m_img;
12     cv::Mat m_canny;
13 public:
14     EdgeDetection(cv::Mat iamge);
15     bool cannyProcess(unsigned int downThreshold,unsigned int upThreshold);
16     bool getContours();
17     
18     ~EdgeDetection();
19 };

EdgeDetection.cpp

 1 #include "EdgeDetection.h"
 2 
 3 EdgeDetection::EdgeDetection(cv::Mat image)
 4 {
 5     m_img = image;
 6 }
 7 
 8 bool EdgeDetection::cannyProcess(unsigned int downThreshold, unsigned int upThreshold)
 9 {
10     bool ret=true;
11 
12     if (m_img.empty())
13     {
14         ret = false;
15     }
16 
17     cv::Canny(m_img, m_canny, downThreshold, upThreshold);
18     cv::imshow("Canny", m_canny); 
19 
20     return ret;
21 }
22 
23 bool EdgeDetection::getContours()
24 {
25     bool ret = true;
26     if (m_canny.empty())
27     {
28         ret = false;
29     }
30     
31     cv::Mat k = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3), cv::Point(-1, -1));
32     cv::dilate(m_canny, m_canny, k);
33     imshow("dilate", m_canny);
34     
35     // 輪廓發現與繪制
36     vector<vector<cv::Point> > contours;
37     vector<Vec4i> hierarchy;
38     findContours(m_canny, contours, cv::RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point());
39 
40     for (size_t i = 0; i < contours.size();++i)
41     {
42         // 最大外接輪廓
43         cv::Rect rect = cv::boundingRect(contours[i]);
44         cv::rectangle(m_img,rect,cv::Scalar(0,255,0),2,LINE_8);
45 
46 
47         // 最小外接輪廓
48         RotatedRect rrt = minAreaRect(contours[i]);
49         Point2f pts[4];
50         rrt.points(pts);
51         // 繪制旋轉矩形與中心位置
52         for (int i = 0; i < 4; i++) {
53             line(m_img, pts[i % 4], pts[(i + 1) % 4], Scalar(0, 0, 255), 2, 8, 0);
54         }
55         Point2f cpt = rrt.center;
56         circle(m_img, cpt, 2, Scalar(255, 0, 0), 2, 8, 0);
57     }
58 
59 
60 
61 
62 
63     imshow("contours", m_img);
64     return ret;
65 }
66 
67 EdgeDetection::~EdgeDetection()
68 {
69 }

main.cpp

#include"EdgeDetection.h"
using namespace std;
using namespace cv;



int main(int argc, char* argv[])
{
    Mat src = imread("rect.jpg");
    if (src.empty())
    {
        cout << "image is empty" << endl;
        return -1;
    }

    imshow("input", src);

    EdgeDetection ed(src);

    ed.cannyProcess(80,160);
    ed.getContours();

    waitKey(0);
    return 0;
}

原圖

 

 canny

 

 目標圖

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM