kongen kongen
首页
导航站
  • 学习教程

    • Opencv教程
    • C++基础教程
    • C++_Primer教程
    • CUDA编程
  • Opencv
  • CNN
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 面试题库

    • HTML
    • CSS
    • jQuery
    • Vue
    • 零碎
  • 面试心得

    • 杂言碎语
  • 十架道路

    • 十架七言系列
    • 基督徒生活观
    • 上帝的蓝图
  • 摘抄收录

    • ☆ 励志鸡汤
    • ❀ 人间烟火
  • 读书笔记

    • 《小狗钱钱》
    • 《穷爸爸富爸爸》
    • 《聪明人使用方格笔记本》
  • 学习
  • 面试
  • 心情杂货
  • 友情链接
关于
  • 网站
  • 资源
  • Vue资源
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Kongen

你好呀(✪ω✪)
首页
导航站
  • 学习教程

    • Opencv教程
    • C++基础教程
    • C++_Primer教程
    • CUDA编程
  • Opencv
  • CNN
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 面试题库

    • HTML
    • CSS
    • jQuery
    • Vue
    • 零碎
  • 面试心得

    • 杂言碎语
  • 十架道路

    • 十架七言系列
    • 基督徒生活观
    • 上帝的蓝图
  • 摘抄收录

    • ☆ 励志鸡汤
    • ❀ 人间烟火
  • 读书笔记

    • 《小狗钱钱》
    • 《穷爸爸富爸爸》
    • 《聪明人使用方格笔记本》
  • 学习
  • 面试
  • 心情杂货
  • 友情链接
关于
  • 网站
  • 资源
  • Vue资源
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • OpenCV简介

  • OpenCV中的 Gui特性

  • 核心操作

  • OpenCV中的图像处理

    • 改变颜色空间
    • 图像的几何变换
    • 图像阈值
    • 图像滤波
    • 形态变换
    • 图形梯度
    • Canny边缘检测
    • 图像金字塔
    • 轮廓:入门
    • 轮廓特征
    • 轮廓属性
    • 轮廓:更多函数
    • 轮廓:层次结构
      • 理论
      • 什么是层次结构?
      • OpenCV中的层次结构表示
      • 轮廓检索模式
    • 直方图1:查找,绘画,分析
    • 直方图2:均衡直方图
    • 直方图3:2D直方图
    • 反投影直方图
    • 傅里叶变换
    • 模板匹配
    • 霍夫线变换
    • 霍夫圆变换
    • 基于GrabCut算法的交互式前景提取
    • 基于分水岭算法的图像分割
  • 特征检测和描述

  • 视频分析

  • 相机校准和3D重建

  • 机器学习

  • 计算摄影

  • 目标检测

  • Opencv基础原理
  • OpenCV中的图像处理
kongen
2019-06-11
目录

轮廓:层次结构

# 理论

在最近几篇关于轮廓的文章中,我们使用了与OpenCV提供的轮廓相关的几个函数。但是当我们使用cv.findContours()函数在图像中找到轮廓时,我们已经传递了一个参数Contour Retrieval Mode。我们通常传递cv.RETR_LIST或cv.RETR_TREE,它运行的效果很好。但它究竟意味着什么?

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

这就是我们将在本文中处理的内容。

# 什么是层次结构?

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

考虑下面的示例图片:

image41

在这张图片中,有一些形状,我从0-5编号。图2和2a表示最外侧盒子的外部和内部轮廓。

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

接下来是轮廓-2a。它可以被认为是轮廓-2的子节点(或者相反,轮廓-2是轮廓-2的父节点)。所以让它在层次结构-1中。类似地,轮廓-3是轮廓-2的子,它进入下一层次。最后,轮廓4,5是轮廓-3a的子节点,它们位于最后的层次结构级别。从我编号框的方式,我会说轮廓-4是轮廓-3a的第一个孩子(它也可以是轮廓-5)。

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

# OpenCV中的层次结构表示

因此每个轮廓都有自己的信息,关于它是什么层次结构,谁是它的子,谁是它的父等.OpenCV将它表示为四个值的数组:[Next,Previous,First_Child,Parent]

“下一个表示同一层级的下一个轮廓。”

例如,在我们的图片中取出contour-0。谁是同一水平的下一个轮廓?它是轮廓-1。所以简单地说Next = 1.类似地,对于Contour-1,next是contour-2。所以Next = 2。

轮廓-2怎么样?同一级别没有下一个轮廓。所以简单地说,将Next = -1。轮廓-4怎么样?它与contour-5处于同一水平。所以它的下一个轮廓是轮廓-5,所以Next = 5。

“上一个表示同一层级的先前轮廓。”

与上述相同。轮廓-1的先前轮廓在同一水平面上为轮廓-0。类似地,对于轮廓-2,它是轮廓-1。而对于contour-0,没有先前的,所以把它作为-1。

“First_Child表示其第一个子轮廓。”

无需任何解释。对于轮廓-2,孩子是轮廓-2a。因此它获得了contour-2a的相应索引值。轮廓-3a怎么样?它有两个孩子。但我们只带第一个孩子。它是轮廓-4。因此,对于轮廓-3a,First_Child = 4。

“父表示其父轮廓的索引。”

它与First_Child相反。对于轮廓-4和轮廓-5,父轮廓都是轮廓-3a。对于轮廓-3a,它是轮廓-3,依此类推。

注意:如果没有子项或父项,则该字段将被视为-1

所以现在我们知道OpenCV中使用的层次结构样式,我们可以在上面给出的相同图像的帮助下检查OpenCV中的Contour Retrieval Modes。即cv.RETR_LIST,cv.RETR_TREE,cv.RETR_CCOMP,cv.RETR_EXTERNAL等标志是什么意思?

# 轮廓检索模式

  1. RETR_LIST

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

所以这里,层次结构数组中的第3和第4项始终为-1。但显然,Next和Previous术语将具有相应的值。请自行检查并验证。

下面是我得到的结果,每行是相应轮廓的层次结构细节。例如,第一行对应于轮廓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]]])
1
2
3
4
5
6
7
8
9

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

  1. RETR_EXTERNAL

如果使用此标志,则仅返回极端外部标志。所有儿童轮廓都被遗忘。我们可以说,根据这项法律,只有每个家庭中最年长的人才能得到照顾。它并不关心其他家庭成员:)。

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

>>> hierarchy
array([[[ 1, -1, -1, -1],
        [ 2,  0, -1, -1],
        [-1,  1, -1, -1]]])
1
2
3
4

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

  1. RETR_CCOMP

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

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

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

image42

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

现在采取轮廓-1。它在层次结构-2中。同一层次中的下一个(在轮廓-1的父下面)是轮廓-2。没有前一个。没有子,但父是轮廓-0。所以数组是[2,-1,-1,0]。

类似于contour-2:它在层次结构-2中。在contour-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]]])
1
2
3
4
5
6
7
8
9
10
  1. RETR_TREE

这是最后一个人,Mr.Perfect。它检索所有轮廓并创建完整的族层次结构列表。它甚至告诉,谁是爷爷,父,子,孙子,甚至超越...... 😃。

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

image43

取contour-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]]])
1
2
3
4
5
6
7
8
9
10
编辑 (opens new window)
轮廓:更多函数
直方图1:查找,绘画,分析

← 轮廓:更多函数 直方图1:查找,绘画,分析→

最近更新
01
附录L_CUDA底层驱动API
02-08
02
附录K_CUDA计算能力
02-08
03
附录J纹理获取
02-08
更多文章>
Theme by Vdoing | Copyright © 2024-2025 Kongen | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×