天天看點

OpenCV2-------findContours函數參數詳解 文章來源:點選打開

 文章來源:點選打開

注: 這篇文章用的OpenCV版本是2.4.10, 3以上的OpenCV版本相關函數可能有改動

Opencv中通過使用findContours函數,簡單幾個的步驟就可以檢測出物體的輪廓,很友善。這些準備繼續探讨一下

findContours方法中各參數的含義及用法,比如要求隻檢測最外層輪廓該怎麼辦?contours裡邊的資料結構是怎樣

的?hierarchy到底是什麼鬼?Point()有什麼用?

先從findContours函數原型看起:

  1. findContours( InputOutputArray image, OutputArrayOfArrays contours,
  2. OutputArray hierarchy, int mode,
  3. int method, Point offset=Point());

第一個參數:image,單通道圖像矩陣,可以是灰階圖,但更常用的是二值圖像,一般是經過Canny、拉普拉斯等邊

                     緣檢測算子處理過的二值圖像;

第二個參數:contours,定義為“vector<vector<Point>> contours”,是一個向量,并且是一個雙重向量,向量

           内每個元素儲存了一組由連續的Point點構成的點的集合的向量,每一組Point點集就是一個輪廓。  

           有多少輪廓,向量contours就有多少元素。

第三個參數:hierarchy,定義為“vector<Vec4i> hierarchy”,先來看一下Vec4i的定義:

                           typedef    Vec<int, 4>   Vec4i;                                                                                                                                       

           Vec4i是Vec<int,4>的别名,定義了一個“向量内每一個元素包含了4個int型變量”的向量。

           是以從定義上看,hierarchy也是一個向量,向量内每個元素儲存了一個包含4個int整型的數組。

           向量hiararchy内的元素和輪廓向量contours内的元素是一一對應的,向量的容量相同。

           hierarchy向量内每一個元素的4個int型變量——hierarchy[i][0] ~hierarchy[i][3],分别表示第

        i個輪廓的後一個輪廓、前一個輪廓、父輪廓、内嵌輪廓的索引編号。如果目前輪廓沒有對應的後一個

        輪廓、前一個輪廓、父輪廓或内嵌輪廓的話,則hierarchy[i][0] ~hierarchy[i][3]的相應位被設定為

        預設值-1。

第四個參數:int型的mode,定義輪廓的檢索模式:

           取值一:CV_RETR_EXTERNAL隻檢測最外圍輪廓,包含在外圍輪廓内的内圍輪廓被忽略

           取值二:CV_RETR_LIST   檢測所有的輪廓,包括内圍、外圍輪廓,但是檢測到的輪廓不建立等級關

                  系,彼此之間獨立,沒有等級關系,這就意味着這個檢索模式下不存在父輪廓或内嵌輪廓,

                  是以hierarchy向量内所有元素的第3、第4個分量都會被置為-1,具體下文會講到

           取值三:CV_RETR_CCOMP  檢測所有的輪廓,但所有輪廓隻建立兩個等級關系,外圍為頂層,若外圍

                  内的内圍輪廓還包含了其他的輪廓資訊,則内圍内的所有輪廓均歸屬于頂層

           取值四:CV_RETR_TREE, 檢測所有輪廓,所有輪廓建立一個等級樹結構。外層輪廓包含内層輪廓,内

                   層輪廓還可以繼續包含内嵌輪廓。

第五個參數:int型的method,定義輪廓的近似方法:

           取值一:CV_CHAIN_APPROX_NONE 儲存物體邊界上所有連續的輪廓點到contours向量内

           取值二:CV_CHAIN_APPROX_SIMPLE 僅儲存輪廓的拐點資訊,把所有輪廓拐點處的點儲存入contours

                   向量内,拐點與拐點之間直線段上的資訊點不予保留

           取值三和四:CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS使用teh-Chinl chain 近

                   似算法

第六個參數:Point偏移量,所有的輪廓資訊相對于原始圖像對應點的偏移量,相當于在每一個檢測出的輪廓點上加

            上該偏移量,并且Point還可以是負值!

下邊用效果圖對比一下findContours函數中各參數取不同值時,向量contours和hierarchy的内容如何變化,有何

異同。

主體程式如下:

  1. #include "core/core.hpp"
  2. #include "highgui/highgui.hpp"
  3. #include "imgproc/imgproc.hpp"
  4. #include "iostream"
  5. using namespace std;
  6. using namespace cv;
  7. int main(int argc,char *argv[])
  8. {
  9. Mat imageSource=imread(argv[ ], );
  10. imshow( "Source Image",imageSource);
  11. Mat image;
  12. GaussianBlur(imageSource,image,Size( , ), );
  13. Canny(image,image, , );
  14. vector< vector<Point>> contours;
  15. vector<Vec4i> hierarchy;
  16. findContours(image,contours,hierarchy,RETR_TREE,CHAIN_APPROX_SIMPLE,Point());
  17. Mat imageContours=Mat::zeros(image.size(),CV_8UC1);
  18. Mat Contours=Mat::zeros(image.size(),CV_8UC1); //繪制
  19. for( int i= ;i<contours.size();i++)
  20. {
  21. //contours[i]代表的是第i個輪廓,contours[i].size()代表的是第i個輪廓上所有的像素點數
  22. for( int j= ;j<contours[i].size();j++)
  23. {
  24. //繪制出contours向量内所有的像素點
  25. Point P=Point(contours[i][j].x,contours[i][j].y);
  26. Contours.at<uchar>(P)= ;
  27. }
  28. //輸出hierarchy向量内容
  29. char ch[ ];
  30. sprintf(ch, "%d",i);
  31. string str=ch;
  32. cout<< "向量hierarchy的第" <<str<< " 個元素内容為:"<< endl<<hierarchy[i]<< endl<< endl;
  33. //繪制輪廓
  34. drawContours(imageContours,contours,i,Scalar( ), , ,hierarchy);
  35. }
  36. imshow( "Contours Image",imageContours); //輪廓
  37. imshow( "Point of Contours",Contours); //向量contours内儲存的所有輪廓點集
  38. waitKey( );
  39. return ;
  40. }

程式中所用原始圖像如下:

OpenCV2-------findContours函數參數詳解 文章來源:點選打開

通過調整第四個參數mode——輪廓的檢索模式、第五個參數method——輪廓的近似方式和不同的偏移量Point(),就可以得到以下效果。

一、mode取值“CV_RETR_EXTERNAL”,method取值“CV_CHAIN_APPROX_NONE”,即隻檢測最外層輪廓,并且儲存輪廓上所有點:

輪廓:

OpenCV2-------findContours函數參數詳解 文章來源:點選打開

隻有最外層的輪廓被檢測到,内層的輪廓被忽略

contours向量内所有點集:

OpenCV2-------findContours函數參數詳解 文章來源:點選打開

儲存了所有輪廓上的所有點,圖像表現跟輪廓一緻

hierarchy向量:

OpenCV2-------findContours函數參數詳解 文章來源:點選打開

重溫一下hierarchy向量————向量中每個元素的4個整形分别對應目前輪廓的後一個輪廓、前一個輪廓、父輪廓、内

嵌輪廓的索引編号。

本次參數配置下,hierarchy向量内有3個元素,分别對應于3個輪廓。以第2個輪廓(對應向量内第1個元素)為例,

内容為[2,0,-1,-1], “2”表示目前輪廓的後一個輪廓的編号為2,“0”表示目前輪廓的前一個輪廓編号為0,其後2

個“-1”表示為空,因為隻有最外層輪廓這一個等級,是以不存在父輪廓和内嵌輪廓。

二、 mode取值“CV_RETR_LIST”,method取值“CV_CHAIN_APPROX_SIMPLE”,即檢測所有輪廓,但各輪廓之間彼此獨立,不建立等級關系,并且僅儲存輪廓上拐點資訊:

檢測到的輪廓跟上文“一”中是一緻的,不再顯示。

contours向量内所有點集:

OpenCV2-------findContours函數參數詳解 文章來源:點選打開

contours向量中所有的拐點資訊得到了保留,但是拐點與拐點之間直線段的部分省略掉了。

hierarchy向量(截取一部分):

OpenCV2-------findContours函數參數詳解 文章來源:點選打開

本次參數配置下,檢測出了較多輪廓。第1、第2個整形值分别指向上一個和下一個輪廓編号,由于本次配置mode取

值“RETR_LIST”,各輪廓間各自獨立,不建立等級關系,是以第3、第4個整形參數為空,設為值-1。

三、mode取值“CV_RETR_TREE”,method取值“CV_CHAIN_APPROX_NONE”,即檢測所有輪廓,輪廓間建立外層、内層的等級關系,并且儲存輪廓上所有點。

contours向量内所有點集:

OpenCV2-------findContours函數參數詳解 文章來源:點選打開

所有内外層輪廓都被檢測到,contours點集組成的圖形跟輪廓表現一緻。

hierarchy向量(截取一部分)

OpenCV2-------findContours函數參數詳解 文章來源:點選打開

本次參數配置要求檢測所有輪廓,每個輪廓都被劃分等級,最外圍、第一内圍、第二内圍等等,是以除第1個最後一

個輪廓外,其他輪廓都具有不為-1的第3、第4個整形參數,分别指向目前輪廓的父輪廓、内嵌輪廓索引編号。

四、Point()偏移量設定

使用三中的參數配置,設定偏移量Point為Point(45,30)。

此時輪廓圖像為:

OpenCV2-------findContours函數參數詳解 文章來源:點選打開

可以看到輪廓圖像整體向右下角有一個偏轉,偏轉量就是設定的(45,30)。

這個偏移量的設定不能過大或過小(負方向上的過小),若圖像上任一點加上該偏移量後超出圖像邊界,程式會記憶體

溢出報錯。

findContours函數的各參數就探讨到此,其他參數配置的情況大同小異。值得關注一下的是繪制輪廓的函數

drawContours中最後一個參數是一個Point類型的offset,這個offset跟findContours函數中的offset含義一緻,設定之

後所繪制的輪廓是原始輪廓上所有像素點加上該偏移量offset後的效果。

當所分析圖像是另外一個圖像的ROI的時候,這個offset偏移量就可以大顯身手了。通過加減這個偏移量,就可以把

ROI圖像的檢測結果投影到原始圖像對應位置上。