OpenCV-Python 轮廓分层 | 二十五
目標(biāo)
這次我們學(xué)習(xí)輪廓的層次,即輪廓中的父子關(guān)系。
理論
在前幾篇關(guān)于輪廓的文章中,我們已經(jīng)討論了與OpenCV提供的輪廓相關(guān)的幾個函數(shù)。但是當(dāng)我們使用cv.findcontour()函數(shù)在圖像中找到輪廓時,我們已經(jīng)傳遞了一個參數(shù),輪廓檢索模式。我們通常通過了cv.RETR_LIST或cv.RETR_TREE,效果很好。但這到底意味著什么呢?
另外,在輸出中,我們得到了三個數(shù)組,第一個是圖像,第二個是輪廓,還有一個我們命名為hierarchy的輸出(請檢查前面文章中的代碼)。但我們從未在任何地方使用過這種層次結(jié)構(gòu)。那么這個層級是什么?它是用來做什么的?它與前面提到的函數(shù)參數(shù)有什么關(guān)系?
這就是我們在本文中要討論的內(nèi)容。
層次結(jié)構(gòu)是什么?
通常我們使用cv.findcontour()函數(shù)來檢測圖像中的對象,對吧?有時對象在不同的位置。但在某些情況下,某些形狀在其他形狀中。就像嵌套的圖形一樣。在這種情況下,我們把外部的稱為父類,把內(nèi)部的稱為子類。這樣,圖像中的輪廓就有了一定的相互關(guān)系。我們可以指定一個輪廓是如何相互連接的,比如,它是另一個輪廓的子輪廓,還是父輪廓等等。這種關(guān)系的表示稱為層次結(jié)構(gòu)。
下面是一個例子:
在這張圖中,有一些形狀我已經(jīng)從0-5開始編號。2和2a表示最外層盒子的外部和內(nèi)部輪廓。
這里,等高線0,1,2在外部或最外面。我們可以說,它們在層級-0中,或者簡單地說,它們在同一個層級中。
其次是contour-2a。它可以被認(rèn)為是contour-2的子級(或者反過來,contour-2是contour-2a的父級)。假設(shè)它在層級-1中。類似地,contour-3是contour-2的子級,它位于下一個層次結(jié)構(gòu)中。最后,輪廓4,5是contour-3a的子級,他們在最后一個層級。從對方框的編號來看,我認(rèn)為contour-4是contour-3a的第一個子級(它也可以是contour-5)。
我提到這些是為了理解一些術(shù)語,比如相同層級,外部輪廓,子輪廓,父輪廓,第一個子輪廓等等。現(xiàn)在讓我們進(jìn)入OpenCV。
OpenCV中的分級表示
所以每個輪廓都有它自己的信息關(guān)于它是什么層次,誰是它的孩子,誰是它的父母等等。OpenCV將它表示為一個包含四個值的數(shù)組:[Next, Previous, First_Child, Parent]
“Next表示同一層次的下一個輪廓。”
例如,在我們的圖片中取contour-0。誰是下一個同級別的等高線?這是contour-1。簡單地令Next = 1。類似地,Contour-1也是contour-2。所以Next = 2。
contour-2呢?同一水平線上沒有下一條等高線。簡單地,讓Next = -1。contour-4呢?它與contour-5處于同一級別。它的下一條等高線是contour-5,所以next = 5。
“Previous表示同一層次上的先前輪廓。”
和上面一樣。contour-1之前的等值線為同級別的contour-0。類似地,contour-2也是contour-1。對于contour-0,沒有前項(xiàng),所以設(shè)為-1。
“First_Child表示它的第一個子輪廓。”
沒有必要作任何解釋。對于contour-2, child是contour-2a。從而得到contour-2a對應(yīng)的指標(biāo)值。contour-3a呢?它有兩個孩子。但我們只關(guān)注第一個孩子。它是contour-4。那么First_Child = 4 對contour-3a而言。
“Parent表示其父輪廓的索引。”
它與First_Child相反。對于輪廓線-4和輪廓線-5,父輪廓線都是輪廓線-3a。對于輪廓3a,它是輪廓-3,以此類推。
注意
如果沒有子元素或父元素,則該字段被視為-1
現(xiàn)在我們已經(jīng)了解了OpenCV中使用的層次樣式,我們可以借助上面給出的相同圖像來檢查OpenCV中的輪廓檢索模式。一些標(biāo)志如 cv.RETR_LIST, cv.RETR_TREE,cv.RETR_CCOMP, cv.RETR_EXTERNAL等等的含義。
輪廓檢索模式
1. RETR_LIST
這是四個標(biāo)志中最簡單的一個(從解釋的角度來看)。它只是檢索所有的輪廓,但不創(chuàng)建任何親子關(guān)系。在這個規(guī)則下,父輪廓和子輪廓是平等的,他們只是輪廓。他們都屬于同一層級。
這里,第3和第4項(xiàng)總是-1。但是很明顯,下一項(xiàng)和上一項(xiàng)都有對應(yīng)的值。你自己檢查一下就可以了。
下面是我得到的結(jié)果,每一行是對應(yīng)輪廓的層次細(xì)節(jié)。例如,第一行對應(yīng)于輪廓0。下一條輪廓是輪廓1。所以Next = 1。沒有先前的輪廓,所以Previous=-1。剩下的兩個,如前所述,是-1。
>>> hierarchy
array([[[ 1, -1, -1, -1],
[ 2, 0, -1, -1],
[ 3, 1, -1, -1],
[ 4, 2, -1, -1],
[ 5, 3, -1, -1],
[ 6, 4, -1, -1],
[ 7, 5, -1, -1],
[-1, 6, -1, -1]]])
如果您沒有使用任何層次結(jié)構(gòu)特性,那么這是在您的代碼中使用的最佳選擇。
2. RETR_EXTERNAL
如果使用此標(biāo)志,它只返回極端外部標(biāo)志。所有孩子的輪廓都被留下了。我們可以說,根據(jù)這項(xiàng)規(guī)則,每個家庭只有長子得到關(guān)注。它不關(guān)心家庭的其他成員:)。
所以在我們的圖像中,有多少個極端的外輪廓?在等級0級?有3個,即等值線是0 1 2,對吧?現(xiàn)在試著用這個標(biāo)志找出等高線。這里,給每個元素的值與上面相同。并與上述結(jié)果進(jìn)行了比較。以下是我得到的:
>>> hierarchy
array([[[ 1, -1, -1, -1],
[ 2, 0, -1, -1],
[-1, 1, -1, -1]]])
如果只想提取外部輪廓,可以使用此標(biāo)志。它在某些情況下可能有用。
3. RETR_CCOMP
此標(biāo)志檢索所有輪廓并將其排列為2級層次結(jié)構(gòu)。物體的外部輪廓(即物體的邊界)放在層次結(jié)構(gòu)-1中。對象內(nèi)部孔洞的輪廓(如果有)放在層次結(jié)構(gòu)-2中。如果其中有任何對象,則其輪廓僅在層次結(jié)構(gòu)1中重新放置。以及它在層級2中的漏洞等等。
只需考慮在黑色背景上的“白色的零”圖像。零的外圓屬于第一級,零的內(nèi)圓屬于第二級。
我們可以用一個簡單的圖像來解釋它。這里我用紅色標(biāo)注了等高線的順序和它們所屬的層次,用綠色標(biāo)注(1或2),順序與OpenCV檢測等高線的順序相同。
考慮第一個輪廓,即contour-0。這是hierarchy-1。它有兩個孔,分別是等高線1和2,屬于第二級。因此,對于輪廓-0,在同一層次的下一個輪廓是輪廓-3。previous也沒有。在hierarchy-2中,它的第一個子結(jié)點(diǎn)是contour-1。它沒有父類,因?yàn)樗趆ierarchy-1中。所以它的層次數(shù)組是[3,-1,1,-1]
現(xiàn)在contour-1。它在層級-2中。相同層次結(jié)構(gòu)中的下一個(在contour-1的父母關(guān)系下)是contour-2。沒有previous。沒有child,但是parent是contour-0。所以數(shù)組是[2,-1,-1,0]
類似的contour-2:它在hierarchy-2中。在contour-0下,同一層次結(jié)構(gòu)中沒有下一個輪廓。所以沒有Next。previous是contour-1。沒有child,parent是contour0。所以數(shù)組是[-1,1,-1,0]
contour-3:層次-1的下一個是輪廓-5。以前是contour-0。child是contour4,沒有parent。所以數(shù)組是[5,0,4,-1]
contour-4:它在contour-3下的層次結(jié)構(gòu)2中,它沒有兄弟姐妹。沒有next,沒有previous,沒有child,parent是contour-3。所以數(shù)組是[-1,-1,-1,3]
剩下的你可以補(bǔ)充。這是我得到的最終答案:
>>> hierarchy
array([[[ 3, -1, 1, -1],
[ 2, -1, -1, 0],
[-1, 1, -1, 0],
[ 5, 0, 4, -1],
[-1, -1, -1, 3],
[ 7, 3, 6, -1],
[-1, -1, -1, 5],
[ 8, 5, -1, -1],
[-1, 7, -1, -1]]])
4. RETR_TREE
這是最后一個家伙,完美先生。它檢索所有的輪廓并創(chuàng)建一個完整的家族層次結(jié)構(gòu)列表。它甚至告訴,誰是爺爺,父親,兒子,孫子,甚至更多…
以上是生活随笔為你收集整理的OpenCV-Python 轮廓分层 | 二十五的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
總結(jié)
- 上一篇: Lucene 个人领悟 (一)
- 下一篇: 与app交互因异步造成的坑记录