OpenCV-Python轮廓层次结构

了解轮廓层次结构,这次,我们了解轮廓的层次结构,即Contours中的父子关系。

在有关轮廓的最后几篇文章中,我们使用了与OpenCV提供的轮廓相关的一些功能。但是,当我们使用 cv.findContours() 函数在图像中找到轮廓时,我们传递了一个参数,即 Contour Retrieval Mode 。我们通常通过 cv.RETR_LISTcv.RETR_TREE ,效果很好。但这实际上是什么意思?

另外,在输出中,我们得到了三个数组,第一个是图像,第二个是轮廓,另一个是我们命名为层次结构的输出(请检查上一篇文章中的代码)。但是,我们从未在任何地方使用此层次结构。那么,这个层次结构是什么呢?它与前面提到的函数参数有什么关系?

这就是本文要处理的内容。

什么是轮廓层次结构

通常我们使用 cv.findContours() 函数来检测图像中的对象,对吗?有时对象位于不同的位置。但是在某些情况下,某些形状位于其他形状内。就像嵌套的数字一样。在这种情况下,我们将外部的一个称为 父级 ,将内部的一个称为 子级 。这样,图像中的轮廓彼此之间就具有某种关系。并且我们可以指定一个轮廓如何相互连接,例如是其他轮廓的子轮廓,还是父轮廓等。这种关系的表示称为 层次结构

考虑下面的示例图像:

什么是轮廓层次结构

在此图像中,我从 0-5 编号了一些形状。2和2a表示最外面的盒子的外部和内部轮廓。

在此,轮廓0,1,2在 外部或最外部 。我们可以说,它们处于 0层次结构 中,或者只是处于 相同的层次结构级别 中。

接下来是 轮廓2a 。可以将其视为 轮廓2的子级 (或者相反,轮廓2是轮廓2a的父级)。因此,将其设置为 hierarchy-1 。同样,contour-3是contour-2的子级,位于下一个层次结构中。最后,轮廓4,5是轮廓3a的子级,它们位于最后的层次结构级别。从编号方式上来说,轮廓4是轮廓3a的第一个子元素(也可以是轮廓5)。

我提到这些东西是为了理解诸如相同的层次结构级别,外部轮廓,子轮廓,父轮廓,第一个孩子等术语。现在让我们进入OpenCV

OpenCV中的轮廓层次结构表示

因此,每个轮廓都有关于其层次结构,其子级,其父级等的信息。OpenCV将其表示为四个值的数组:[Next,Previous,First_Child,Parent]

Next 表示相同等级的下一个轮廓
例如,在我们的图片中选择轮廓0。谁是同一级别的下一个轮廓?它是轮廓1。因此,只需将Next = 1放进去。同样对于Contour-1,下一个就是轮廓线2。所以下一个= 2。

那轮廓2呢?在同一层中没有下一个轮廓。简而言之,将Next = -1。那轮廓4呢?与轮廓5处于同一水平。所以它的下一个轮廓是轮廓5,所以Next = 5。

Previous 表示相同轮廓级别的上一个轮廓
和上面一样。轮廓1的先前轮廓是同一级别的轮廓0。同样对于轮廓2,它是轮廓1。对于轮廓0,没有先前值,因此将其设为-1。

First_Child 表示其第一个子轮廓
无需任何解释。对于轮廓2,子级是轮廓2a。这样就得到了轮廓2a的相应索引值。那轮廓3a呢?它有两个孩子。但是我们只带第一个孩子。它是轮廓4。因此,轮廓3a的First_Child = 4。

Parent 代表示其父代轮廓的索引
它与First_Child相反。轮廓4和轮廓5的父轮廓均为轮廓3a。对于轮廓3a,它是轮廓3,依此类推。

注意
如果没有孩子或父母,则该字段为-1

因此,现在我们知道了OpenCV中使用的层次结构样式,我们可以借助上面给出的相同图像来检查OpenCV中的轮廓检索模式。即像 cv.RETR_LISTcv.RETR_TREEcv.RETR_CCOMPcv.RETR_EXTERNAL 等标志是什么意思?

轮廓检索模式

RETR_LIST

这是四个标志中最简单的一个(从解释的角度来看)。它仅检索所有轮廓,但不创建任何父子关系。在这个规则下,父母和孩子是平等的,他们只是轮廓。即它们都属于同一层次结构级别。

因此,在这里,层次结构数组中的第3和第4项始终为-1。但是很明显,下一个和上一个术语将具有其相应的值。只需自己检查并验证即可。

以下是我得到的结果,每行是相应轮廓的层次结构详细信息。例如,第一行对应于轮廓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]]])

如果不使用任何层次结构功能,这是在代码中使用的不错选择。

RETR_EXTERNAL

如果使用此标志,则仅返回极端的外部标志。保留所有子轮廓。可以说,根据这项法律,只有每个家庭中的老大才能得到照顾。它不在乎家庭其他成员 :)。

那么,在我们的图像中,有多少个极端的外部轮廓?即在等级0级别?只有3个,即轮廓0,1,2,对吗?现在尝试使用该标志查找轮廓。在此,赋予每个元素的值也与上述相同。与上面的结果进行比较。以下是我得到的:

>>> 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]]])

如果只想提取外部轮廓,则可以使用此标志。在某些情况下可能有用。

RETR_CCOMP

该标志检索所有轮廓并将它们排列为2级层次结构。即,对象的外部轮廓(即其边界)位于层次1中。然后,将对象(如果有)中的孔的轮廓放置在层次2中。如果其中有任何对象,则其轮廓将仅再次放置在等级1中。以及它在等级2中的漏洞等等。

只需考虑黑色背景上的“白色大零”图像即可。零外圈属于第一层级,零内圈属于第二层级。

我们可以用一个简单的图像来解释它。在这里,我用红色标记了轮廓的顺序,并用绿色(1或2)标记了它们所属的层次。该顺序与OpenCV检测轮廓的顺序相同。

RETR_CCOMP

因此考虑第一个轮廓,即轮廓0。它是等级1。它有两个孔,轮廓1和2,它们属于层次2。因此,对于轮廓0,相同层次结构级别中的下一个轮廓为轮廓3。而且没有以前的。它的第一个子对象是层次结构2中的轮廓1。它没有父级,因为它位于1层级中。因此其层次结构数组为 [3,-1,1,-1]

现在取轮廓1。它在等级2中。在同一层次结构中(轮廓1的父项下)下一个是轮廓2。没有上一个。没有孩子,但父母的轮廓为0。因此数组为 [2,-1,-1,0]。

同样的轮廓2:它位于层次2中。在轮廓-0下的相同层次结构中没有下一个轮廓。所以没有下一步。上一个是轮廓1。没有孩子,父母的轮廓为0。因此数组为 [-1,1,-1,0]。

轮廓-3:等级1中的下一个是轮廓5。上一个是轮廓0。孩子是轮廓4,没有父母。因此数组为 [5,0,4,-1]。

轮廓-4:位于轮廓3下的层次2中,并且没有同级。所以没有下一个,没有以前的,没有孩子,父母是轮廓3。因此数组为 [-1,-1,-1,3]。

剩下的可以填满。这是我得到的最终答案:

>>> 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]]])

RETR_TREE

这是最后一个家伙,Perfect先生。它检索所有轮廓并创建完整的族层次列表。它甚至告诉,谁是爷爷,父亲,儿子,孙子甚至更远… :)。

例如,我拍摄了上面的图片,重写了 cv.RETR_TREE 的代码,根据OpenCV给定的结果对轮廓进行重新排序并对其进行分析。同样,红色字母表示轮廓编号,绿色字母表示层次结构顺序。

RETR_TREE

取轮廓0:在层次0中。同一层次结构中的下一个轮廓是轮廓7。没有先前的轮廓。孩子是轮廓1。而且没有父母。因此数组为 [7,-1,1,-1]。

取轮廓2:在等级1中。同一级别无轮廓。没有上一个。孩子是轮廓3。父级是轮廓1。因此数组为 [-1,-1,3,1]。

还有,尝试一下。以下是完整答案:

>>> hierarchy
array([[[ 7, -1,  1, -1],
        [-1, -1,  2,  0],
        [-1, -1,  3,  1],
        [-1, -1,  4,  2],
        [-1, -1,  5,  3],
        [ 6, -1, -1,  4],
        [-1,  5, -1,  4],
        [ 8,  0, -1, -1],
        [-1,  7, -1, -1]]])

Camera课程

Python教程

Java教程

Web教程

数据库教程

图形图像教程

办公软件教程

Linux教程

计算机教程

大数据教程

开发工具教程