图像轮廓分层及其检索模式
目标
在本篇文章中,我们将学习到轮廓的层次及轮廓层次中的4种检索模式,包括以下内容:
- 层次结构是什么?
- 层次结构在OpenCV中的表示
- 4种轮廓检索模式——RETR_LIST、RETR_EXTERNAL、RETR_CCOMP、RETR_TREE
1. 理论
在轮廓绘制及其特征文章中,我们已经讨论了与OpenCV提供的轮廓相关的几个函数,例如查找图像轮廓函数cv2.findContours()
的语法格式如下 :
image,contours,hierarchy = cv2.findContours(image,mode,method)
该函数的各参数解释如下:
- 返回值:
- image:与原始图像中的参数一致
- countours : 返回的轮廓
- hierarchy : 图像的轮廓层次信息
- 函数参数:
- image : 原始图像(8位单通道,所有非零值被处理为1所有零值保持不变,即将灰度图像先采用阈值处理为二值图像)
- mode : 轮廓检索模式
- method : 轮廓的近似方法
注意: OpenCV4.x及以上版本的返回值中没有第一个参数image,即只有countours与hierarchy两个参数
从查找轮廓函数中不难发现,当我们使用cv.findcontour()函数在图像中找轮廓时,我们已经传递了一个参数,轮廓检索模式Contour Retrieval Mode,我们通常会传递cv.RETR_LIST或cv.RETR_TREE而且运行效果很好。但这到底意味着什么呢?
此外,在输出中,我们也得到了三个数组,第一个是图像,第二个是轮廓,还有一个是我们命名为hierarchy的输出(请检查前两篇文章中的代码)。但我们从未在任何地方使用过这种层次结构。那么这个层次结构是什么?它是用来做什么的?它与前面提到的函数参数又有什么关系?
这些问题正是本篇文章所要讨论的内容。
1.1 什么是层次结构
通常我们使用cv.findcontour()函数来检测图像中的对象。但有时对象会在不同的位置,在某些情况下,有一些形状会在其他形状中,就像是嵌套的图形。在这种情况下,我们把外部的形状称为父类,把内部的形状称为子类。这样,图像中的轮廓就有了一定的相互关系。我们可以指定一个轮廓是如何相互连接的,比如,这个轮廓另一个轮廓的子轮廓,还是父轮廓等等。这种关系的表示称为层次结构。
以下面这张图为例并思考其中对应的相互关系
在这张图中,我按照顺序给轮廓从0-5开始编号,其中2和2a分别表示最外层盒子的外部和内部轮廓。
在这里,轮廓0, 1, 2在外部或最外面,即表示向外(external/outermost)轮廓。我们可以说,它们在层级-0(hierarchy-0)中,或者简单地说,它们在同一个层级(same hierarchy level)中。
注意: 为方便描述,本文中的“层次结构”含义等同“层级”。
其次是轮廓-2a。它可以被认为是轮廓-2的子级(或者反过来,轮廓-2是轮廓-2a的父级)。假设它在层级-1中。类似地,轮廓-3是轮廓-2的子级,它位于下一个层次结构中。最后,轮廓4,5是轮廓-3a的子级,他们在最后一个层级,从方框的编号来看,我认为轮廓-4是轮廓-3a的第一个子级(当然它也可以是轮廓-5)。
在这里我们提到的这些是为了理解一些术语,比如相同层级,外部轮廓,子轮廓,父轮廓,第一个子轮廓等等。现在让我们进入OpenCV。
1.2 OpenCV中的层次结构表示
综上所述可知,每个轮廓都有它自己的信息,如层次结构、谁是父轮廓,谁是子轮廓等等。OpenCV将这些信息表示为一个包含四个值的数组: [Next, Previous, First_Child, Parent]
。
Next 表示同一层次上的下一个轮廓。“Next denotes next contour at the same hierarchical level.”、
例如,对于图1中的contour-0,谁是下一个同级别的轮廓?显然是contour-1,所以可以令Next = 1
。类似地,Contour-1同级轮廓中的下一个轮廓是contour-2,所以 令Next = 2
。那么contour-2呢?从上图1中我们可以看出同级别中没有下一个轮廓存在了,其实也很简单,我们直接令 Next = -1。那么contour-4呢?在图1中它与contour-5处于同一级别,所以它的下个轮廓是contour-5,也就是说 Next = 5。
Previous 表示同一层次上的前一个轮廓。“Previous denotes previous contour at the same hierarchical level.”
与上面的分析一样,轮廓contour-1 在同级别的前一个轮廓就是contour-0。类似地,contour-2 同级别的前一个轮廓是 contour-1。对于contour-0,没有前一个轮廓,所以令Previous= -1
。
First_Child表示它的第一个子轮廓。"First_Child denotes its first child contour.”
这里不需要额外的解释,从图中可以看出,对于contour-2的子轮廓是contour-2a,所以它被称作contour-2a,2a 即对应的索引值。那么contour-3a呢?它有两个子轮廓,但我们只关注第一个子轮廓,它是contour-4,那么对contour-3a而言,第一个子轮廓表示为First_Child = 4
。
Parent表示其父轮廓的索引。 “Parent denotes index of its parent contour.”
与First_Child 的相反,对于contour-4和contour-5,父轮廓线都是contour-3a,对于contour-3a,父轮廓线是-3,以此类推。
要点提示: 如果某轮廓没有子轮廓(First_Child)或父轮廓(Parent)&#x