Opencv輪廓檢測(cè)findContours分析(層次結(jié)構(gòu))

Opencv 輪廓檢測(cè)相關(guān)api文檔

  • opencv2的c++接口

官方文檔相關(guān)api

Finds contours in a binary image.

在二值圖像中找到輪廓

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

parameters:

  • image – Source, an 8-bit single-channel image. Non-zero pixels are treated as 1’s. Zero pixels remain 0’s, so the image is treated as binary . You can use compare() , inRange() , threshold() , adaptiveThreshold() , Canny() , and others to create a binary image out of a grayscale or color one. The function modifies the image while extracting the contours. If mode equals to CV_RETR_CCOMP or CV_RETR_FLOODFILL, the input can also be a 32-bit integer image of labels (CV_32SC1).

    輸入圖像是8位單通道的圖像(256級(jí)灰度圖)。其中像素點(diǎn)的非0灰度值被當(dāng)成1,0值保持0。所以輸入圖像被當(dāng)成一個(gè)二值圖像對(duì)待??梢杂胏ompare() , inRange() , threshold() , adaptiveThreshold() , Canny() 或者其他方法來從灰度圖或者彩色圖中生成二值圖像。該函數(shù)在提取輪廓的過程中會(huì)改變圖像。如果模式(mode)CV_RETR_CCOMP 或者 CV_RETR_FLOODFILL,輸入圖像也可以是32位的整型圖像(CV_32SC1)。

  • contours – Detected contours. Each contour is stored as a vector of points.

    找到的輪廓,其中每個(gè)輪廓會(huì)被存儲(chǔ)為vector<Point>,所以contours的類型就是vector<vector<Point>>。

  • hierarchy – Optional output vector, containing information about the image topology. It has as many elements as the number of contours. For each i-th contour contours[i] , the elements hierarchy[i][0] hiearchy[i][1] , hiearchy[i][2] , and hiearchy[i][3] are set to 0-based indices in contours of the next and previous contours at the same hierarchical level, the first child contour and the parent contour, respectively. If for the contour[i] there are no next, previous, parent, or nested contours, the corresponding elements of hierarchy[i] will be negative.

    層次結(jié)構(gòu),可選的輸出向量,包含關(guān)于圖像的拓?fù)浣Y(jié)構(gòu)信息。其具有跟輪廓 數(shù)相同的元素個(gè)數(shù),類型為vector<Vec4i>。對(duì)每個(gè)輪廓,contours[i],其他的懶得翻譯了,也不懂他講的什么意思,只有看了源碼后估計(jì)才能夠知道。

  • mode –Contour retrieval mode

    檢索輪廓的模式。

    • CV_RETR_EXTERNAL retrieves only the extreme outer contours. It sets hierarchy[i][2]=hierarchy[i][3]=-1 for all the contours.就是只提取最外層輪廓,其他的懶得翻譯
    • CV_RETR_LIST retrieves all of the contours without establishing any hierarchical relationships.提取所有輪廓,但是不建立任何層次關(guān)系。。。關(guān)于這個(gè)層次關(guān)系。。有點(diǎn)懵逼。有時(shí)間看下實(shí)現(xiàn)。
    • CV_RETR_CCOMP retrieves all of the contours and organizes them into a two-level hierarchy. At the top level, there are external boundaries of the components. At the second level, there are boundaries of the holes. If there is another contour inside a hole of a connected component, it is still put at the top level.檢索所有輪廓并且將組織成為兩個(gè)級(jí)別層次,頂層是外部邊界,第二層,是洞的邊界。然后如果,有另外一個(gè)輪廓在一個(gè)連通部分的洞中,放到頂層。有毒。。。
    • CV_RETR_TREE retrieves all of the contours and reconstructs a full hierarchy of nested contours. This full hierarchy is built and shown in the OpenCV contours.c demo。檢索所欲的輪廓,并且生成完整的嵌套的輪廓層次結(jié)構(gòu),,真的有毒。完整的層次結(jié)構(gòu)在。。。。。。。。。懶得翻譯了。不過可以看看效果。
  • method –Contour approximation method

    方法,輪廓估計(jì)的方法。

    • CV_CHAIN_APPROX_NONE stores absolutely all the contour points. That is, any 2 subsequent points (x1,y1) and (x2,y2) of the contour will be either horizontal, vertical or diagonal neighbors, that is, max(abs(x1-x2),abs(y2-y1))==1.存儲(chǔ)所有的輪廓點(diǎn),就是說,任何一個(gè)包含一兩個(gè)點(diǎn)的子序列(不改變順序索引的連續(xù)的),兩個(gè)點(diǎn),要么是水平,要么是垂直,要么是對(duì)角的鄰點(diǎn)。也就是說兩個(gè)像素坐標(biāo)的分別的差值的絕對(duì)值最大值等于1.。。媽的,真的有毒,說了這么一堆,不就是兩個(gè)點(diǎn)在坐標(biāo)上相鄰嗎。。
    • CV_CHAIN_APPROX_SIMPLE compresses horizontal, vertical, and diagonal segments and leaves only their end points. For example, an up-right rectangular contour is encoded with 4 points.壓縮水平垂直對(duì)角等,只存儲(chǔ)結(jié)束點(diǎn)什么的,比如矩形就只存儲(chǔ)4個(gè)點(diǎn)。
    • CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS applies one of the flavors of the Teh-Chin chain approximation algorithm. See [TehChin89] for details.不翻譯了,大概是什么近似算法。
  • offset – Optional offset by which every contour point is shifted. This is useful if the contours are extracted from the image ROI and then they should be analyzed in the whole image context.可選的偏移,就是簡(jiǎn)單的平移,特別是在做了ROI步驟之后有用。

翻譯完了官方文檔真不太知道什么意思,特別是什么層次結(jié)構(gòu),說的簡(jiǎn)直有毒。跑例子看一下。

還有一個(gè)相關(guān)的api

Draws contours outlines or filled contours.

畫輪廓

void drawContours(InputOutputArray image, InputArrayOfArrays contours, int contourIdx, const Scalar& color, int thickness=1, int lineType=8, InputArray hierarchy=noArray(), int maxLevel=INT_MAX, Point offset=Point() )

Parameters:
image – Destination image.
contours – All the input contours. Each contour is stored as a point vector.
contourIdx – Parameter indicating a contour to draw. If it is negative, all the contours are drawn.
color – Color of the contours.
thickness – Thickness of lines the contours are drawn with. If it is negative (for example, thickness=CV_FILLED ), the contour interiors are drawn.
lineType – Line connectivity. See line() for details.
hierarchy – Optional information about hierarchy. It is only needed if you want to draw only some of the contours (see maxLevel ).
maxLevel – Maximal level for drawn contours. If it is 0, only the specified contour is drawn. If it is 1, the function draws the contour(s) and all the nested contours. If it is 2, the function draws the contours, all the nested contours, all the nested-to-nested contours, and so on. This parameter is only taken into account when there is hierarchy available.
offset – Optional contour shift parameter. Shift all the drawn contours by the specified \texttt{offset}=(dx,dy) .
contour – Pointer to the first contour.
externalColor – Color of external contours.
holeColor – Color of internal contours (holes).大概解釋在這里,沒什么好翻譯的。

現(xiàn)在開始分析層次結(jié)構(gòu),直接看他的描述有毒

從官方代碼開始

#include "cv.h"
#include "highgui.h"

using namespace cv;
using namespace std;

int main( int argc, char** argv )
{
    Mat src;
    // the first command-line parameter must be a filename of the binary
    // (black-n-white) image
    if( argc != 2 || !(src=imread(argv[1], 0)).data)
        return -1;

    Mat dst = Mat::zeros(src.rows, src.cols, CV_8UC3);

    src = src > 1;
    namedWindow( "Source", 1 );
    imshow( "Source", src );

    vector<vector<Point> > contours;
    vector<Vec4i> hierarchy;

    findContours( src, contours, hierarchy,
        CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );

    // iterate through all the top-level contours,
    // draw each connected component with its own random color
    int idx = 0;
    for( ; idx >= 0; idx = hierarchy[idx][0] )
    {
        Scalar color( rand()&255, rand()&255, rand()&255 );
        drawContours( dst, contours, idx, color, CV_FILLED, 8, hierarchy );
    }

    namedWindow( "Components", 1 );
    imshow( "Components", dst );
    waitKey(0);
}

程序很簡(jiǎn)單,其能夠達(dá)到的效果是將連通的部分用隨機(jī)顏色填充。

效果圖如下

填充效果

確實(shí)將分別連通的兩個(gè)部分填充,很神奇,肯定是用到了那個(gè)層次結(jié)構(gòu),對(duì)層次結(jié)構(gòu)進(jìn)行分析。

那么我先講檢測(cè)到的所有輪廓分別用不同顏色畫出來。代碼很簡(jiǎn)單,就是不停在兩點(diǎn)之間畫線。

    for (size_t i = 0; i < contours[0].size(); i++)
    {
        line(dst, contours[0][i], contours[0][(i + 1) % contours[0].size()], Scalar(0, 255, 0), 1, 8);
    }
    for (size_t i = 0; i < contours[1].size(); i++)
    {
        line(dst, contours[1][i], contours[1][(i + 1) % contours[1].size()], Scalar(0, 0, 255), 1, 8);
    }

    for (size_t i = 0; i < contours[2].size(); i++)
    {
        line(dst, contours[2][i], contours[2][(i + 1) % contours[2].size()], Scalar(255, 0, 0), 1, 8);
    }
    for (size_t i = 0; i < contours[3].size(); i++)
    {
        line(dst, contours[3][i], contours[3][(i + 1) % contours[3].size()], Scalar(255, 255, 255), 1, 8);
    }

由于之前調(diào)試就知道檢測(cè)出來了4條,所以這里才這樣寫簡(jiǎn)單些。
結(jié)果圖

各個(gè)輪廓
  • 綠色第一條
  • 紅色第二條
  • 藍(lán)色底三條
  • 白色第四條

這個(gè)顏色記住,后面分析有用。

現(xiàn)在開始再重新看之前的層次的定義。

hierarchy[i][0] hiearchy[i][1] , hiearchy[i][2] , and hiearchy[i][3] are set to 0-based indices in contours of the next and previous contours at the same hierarchical level, the first child contour and the parent contour, respectively.
這里主要有兩個(gè)概念,或者說兩個(gè)層次,一個(gè)是直接上一個(gè)下一個(gè),好有一個(gè)是父輪廓和子輪廓,很神奇,但是好像有點(diǎn)那個(gè)意思了,有嵌套的感覺。再繼續(xù)分析。把變量都拿出來分析。

contours
hierarchy

可以看到0輪廓的下一條輪廓是2輪廓,2輪廓的下一條-1表示沒有了。
同時(shí)2輪廓的上一條是0,0輪廓的上一條是-1表示沒有。所以這就是最外層的輪廓。

再分析,0輪廓的子輪廓是1輪廓,1輪廓的父輪廓當(dāng)然是0輪廓,再看圖


各個(gè)輪廓

0、1輪廓分別是綠色和紅色,確實(shí)有明顯的包含關(guān)系。到這里就很清楚了。

相當(dāng)于一個(gè)樹形結(jié)構(gòu),上一條下一條針對(duì)同一個(gè)級(jí)別的輪廓,父子輪廓就表示洞類似的結(jié)構(gòu)。

之前源程序的填充方法也可以很簡(jiǎn)單的想處理,判斷是否是父子輪廓之間就行。

到這里輪廓檢測(cè)的基礎(chǔ)部分基本完成,主要其實(shí)就是層次結(jié)構(gòu)的分析,nested這個(gè)描述還是很準(zhǔn)確的,嵌套式的。大概如下圖所示。

結(jié)構(gòu)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,247評(píng)論 6 543
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,520評(píng)論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 178,362評(píng)論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,805評(píng)論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,541評(píng)論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,896評(píng)論 1 328
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,887評(píng)論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,062評(píng)論 0 290
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,608評(píng)論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,356評(píng)論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,555評(píng)論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,077評(píng)論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,769評(píng)論 3 349
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,175評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,489評(píng)論 1 295
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,289評(píng)論 3 400
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,516評(píng)論 2 379

推薦閱讀更多精彩內(nèi)容

  • 謝謝你, 彼時(shí)賦予我這個(gè)時(shí)刻 你應(yīng)該有個(gè)好夢(mèng), 一個(gè)讓你不愿蘇醒的美夢(mèng), 可我又怕我是一陣風(fēng), 把你的夢(mèng)吹碎了, ...
    二兜二年閱讀 272評(píng)論 0 3
  • 遙遠(yuǎn)的清晨是一張著墨不多的素描,你從灰蒙擁擠的人群中出現(xiàn),投我以羞怯的微笑。 ...
    祝方婷閱讀 503評(píng)論 2 3
  • ( 張志軍是從基層報(bào)道組寫稿寫出來的優(yōu)秀人才。他當(dāng)過邯鄲電臺(tái)臺(tái)長(zhǎng)、總編,現(xiàn)任邯鄲記協(xié)主席,出過多部新聞專著,成就輝...
    邯鄲趙金海閱讀 1,462評(píng)論 2 0
  • 不知道大家有沒有這樣的時(shí)候,學(xué)習(xí)太累不學(xué)了吧,那么你以后沒有好工作,生活不好就不要抱怨,因?yàn)檫@是你該得的。 ...
    藍(lán)果果閱讀 427評(píng)論 0 0