一、什么是层次结构
通常我们使用函数cv.findContours()在图片中查找一个对象。有时对象可能位于不同的位置。还有一些情况,一个形状在另外一个形状的内部。这种情况下我们称外部的形状为父,内部的形状为子。按照这种方式分类,一副图像中的所有轮廓之间就建立父子关系。
让我们来看一个简单的例子:
在这个图中,我给这几个形状编号为0-5,2和2a分别代表最外边矩形的外轮廓和内轮廓。
在这里边轮廓0,1,2在外部或最外边,我们可以称它们为(组织结构)第0级,它们属于同一级。
接下来是轮廓2a,它是轮廓2的子轮廓。它是第1级
轮廓3是轮廓2a的子轮廓。它是第2级。
轮廓3a是轮廓3的子轮廓。它是第3级。
轮廓4、5是轮廓3a的子轮廓。它是第4级。轮廓5是轮廓4的下一个轮廓。
二、OpenCV中层次结构
不管层次机构是什么样的,每一个轮廓都包含自己的信息:上一个轮廓是谁,下一个轮廓是谁,父轮廓是谁,子轮廓是谁。
OpenCV使用一个含有四个元素的数组表示:[Next, Previous, First_Child, Parent]。
Next 表示同一级组织结构中的下一个轮廓。
以轮廓0为例,轮廓1就是它的Next。同样,轮廓1的下一个轮廓是轮廓2,next=2.
轮廓2在同一级中没有Next,这是Next=-1,轮廓4的next是轮廓5,轮廓5的next=-1
previous表示统一结构中的前一个轮廓。
轮廓1的previous是轮廓0,轮廓5的previous是轮廓4,轮廓0没有previous,所以previous=-1
first_child表示它的第一个子轮廓
轮廓2的子轮廓是2a,所以它的first_child是2a.轮廓3a有两个子轮廓,但是我们只要第一个子轮廓,所以是轮廓4(按照从上到下,从左到右的顺序排序)
parent 表示它的父轮廓
和子轮廓相反。轮廓4和轮廓5的父轮廓是轮廓3a,而轮廓3a的父轮廓是3。
三、轮廓检索模式
RETR_LIST:
它只是提取所有的轮廓,而不去创建任何父子关系。所有的轮廓都是同一级别。
所以在这种情况下,组织结构数组的第三个、第四个数都是-1,除了第一行和最后一行情况特殊,其他行的next和previous都有对应的值。
我们可以看看数值:
hierarchy:
[[[ 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]]]
RETR_EXTERNAL:
只返回最外边的轮廓,所有的子轮廓都会被忽略。
所以在上图中使用这种模式的话只会返回最外边的轮廓(第0级):轮廓0、1、2。
使用这种模式得到的结果:
hierarchy:
[[[ 1 -1 -1 -1]
[ 2 0 -1 -1]
[-1 1 -1 -1]]]
RETR_CCOMP:
这种模式会返回所有的轮廓,并将轮廓分为两级组织结构。
例如:一个对象的外轮廓为第1级结构。而对象内部中空洞的轮廓为第2级组织结构。空洞中的任何对象的轮廓又是第1级组织结构。空洞的组织结构为第2级。
好吧,我自己也绕晕了,我们在图上看,用红色数字为这些轮廓编号,并用绿色数字代表它们的组织结构。
现在我们考虑轮廓0,它的组织结构是第1级。其中有两个空洞1和2,它们属于第2级组织结构。对于轮廓0来说,和它属于同一级组织结构的下一个(next)是轮廓3,并且没有previous。它的first_child为轮廓1,组织结构为2.由于它是第1级,所以没有父轮廓。因此它的组织结构数组为[3, -1, 1, -1]。
现在是轮廓1,它是第2级。处于同一级的下一个轮廓是2.没有previous,也没有child,父轮廓为0。所以数组是[2, -1, -1, 0]。
其他的以此类推。
RETR_TREE :
这种模式会返回所有的轮廓,并创建一个完整的组织结构列表。它会告诉你谁是爸爸,谁是儿子。
轮廓0的组织结构为0,同一级next为7,没有previous。子轮廓是1,没有父轮廓。所以数组是[7, -1, 1, -1]。
轮廓1的组织结构为1,同一级中没有其他,没有previous。子轮廓是2,父轮廓是0.所以数组是[-1, -1, 2, 0]。
剩下的以此类推。