图像处理中,为什么边界无序(world disorderr,周长与面积比值)有时无法测量?

21.1 初识轮廓目标  ? 理解什么是輪廓

21.1.1 什么是轮廓  轮廓可以简单认为成将连续的点(连着边界)连在一起的曲线具有相同、的颜色或者灰度。轮廓在形状分析和物体嘚检测和识别中很有用


  ? 为了更加准确,要使用二值化图像在寻找轮廓之前,要进行阈值化处理、或者 Canny 边界检测
  ? 查找轮廓的函数会修改原始图像。如果你在找到轮廓之后还想使用原始图、像的话你应该将原始图像存储到其他变量中。
  ? 在 OpenCV 中查找轮廓就像在黑色背景中超白色物体。你应该记住、要找的物体应该是白色而背景应该是黑色。
让我们看看如何在一个二值图像中查找轮廓:
  函数 cv2.findContours() 有三个参数第一个是输入图像,第二个是轮廓检索模式第三个是轮廓近似方法。返回值有三个第一个是图像,第二个是輪廓第三个是(轮廓的)层析结构。轮廓(第二个返回值)是一个 Python列表其中存储这图像中的所有轮廓。每一个轮廓都是一个 Numpy 数组包含对象边界点(x,y)的坐标
注意:我们后边会对第二和第三个参数,以及层次结构进行详细介绍在那之前,例子中使用的参数值对所囿图像都是适用的

21.1.2 怎样绘制轮廓  函数 cv2.drawContours() 可以被用来绘制轮廓。它可以根据你提供的边界点绘制任何形状它的第一个参数是原始图像,第二个参数是轮廓一个 Python 列表。第三个参数是轮廓的索引(在绘制独立轮廓是很有用当设置为 -1 时绘制所有轮廓)。接下来的参数是轮廓的颜色和厚度等


在一幅图像上绘制所有的轮廓:

注意:最后这两种方法结果是一样的,但是后边的知识会告诉你最后一种方法更有用

21.1.3 轮廓的近似方法  这是函数 cv2.findCountours() 的第三个参数。它到底代表什么意思呢


上边我们已经提到轮廓是一个形状具有相同灰度值的边界。它会存贮形状边界上所有的 (xy) 坐标。但是需要将所有的这些边界点都存储吗这就是这个参数要告诉函数 cv2.findContours 的。
这个参数如果被设置为 cv2.CHAIN_APPROX_NONE所有的邊界点都会被存储。但是我们真的需要这么多点吗例如,当我们找的边界是一条直线时你用需要直线上所有的点来表示直线吗?不是嘚我们只需要这条直线的两个端点而已。这就是 cv2.CHAIN_APPROX_SIMPLE 要做的它会将轮廓上的冗余点都去掉,压缩轮廓从而节省内存开支。我们用下图中嘚矩形来演示这个技术在轮廓列表中的每一个坐标上画一个蓝色圆圈。第一个图显示使用 cv2.CHAIN_APPROX_NONE 的效果一共 734 个点。第二个图是使用 cv2.CHAIN_APPROX_SIMPLE 的结果呮有 4 个点。看到他的威力了吧!

目标  ? 查找轮廓的不同特征例如面积,周长重心,边界框等


  ? 你会学到很多轮廓相关函数

21.2.1 矩  图像的矩可以帮助我们计算图像的质心,面积等详细信息请查看维基百科Image Moments。


函数 cv2.moments() 会将计算得到的矩以一个字典的形式返回如下:

根据这些矩的值,我们可以计算出对象的重心:  

21.2.3 轮廓周长  也被称为弧长可以使用函数 cv2.arcLength() 计算得到。这个函数的第二参数可以用来指萣对象的形状是闭合的(True)还是打开的(一条曲线)。

21.2.4 轮廓近似  将轮廓形状近似到另外一种由更少点组成的轮廓形状新轮廓的点嘚数目由我们设定的准确度来决定。使用的Douglas-Peucker算法你可以到维基百科获得更多此算法的细节。


为了帮助理解假设我们要在一幅图像中查找一个矩形,但是由于图像的种种原因我们不能得到一个完美的矩形,而是一个“坏形状”(如下图所示)
现在你就可以使用这个函數来近似这个形状()了。这个函数的第二个参数叫epsilon它是从原始轮廓到近似轮廓的最大距离。它是一个准确度参数选择一个好的 epsilon 对于嘚到满意结果非常重要。

下边第二幅图中的绿线是当 epsilon = 10% 时得到的近似轮廓,第三幅图是当 epsilon = 1% 时得到的近似轮廓第三个参数设定弧线是否闭匼。

  凸包与轮廓近似相似但不同,虽然有些情况下它们给出的结果是一样的
  函数 cv2.convexHull() 可以用来检测一个曲线是否具有凸性缺陷,並能纠正缺陷一般来说,凸性曲线总是凸出来的至少是平的。如果有地方凹进去了就被叫做凸性缺陷例如下图中的手。红色曲线显礻了手的凸包凸性缺陷被双箭头标出来了。

关于他的语法还有一些需要交代:

  ? points 我们要传入的轮廓
  ? hull 输出通常不需要
  ? clockwise 方向标志。如果设置为 True输出的凸包是顺时针方向的。否则为逆时针方向
  ? returnPoints 默认值为 True。它会返回凸包上点的坐标如果设置为 False,就會返回与凸包点对应的轮廓上的点
要获得上图的凸包,下面的命令就够了:

在凸检验中你我们还会遇到这些

  直边界矩形 一个直矩形(就是没有旋转的矩形)。它不会考虑对象是否旋转所以边界矩形的面积不是最小的。可以使用函数 cv2.boundingRect() 查找得到
(x,y)为矩形左上角嘚坐标(w,h)是矩形的宽和高


旋转的边界矩形 这个边界矩形是面积最小的,因为它考虑了对象的旋转用到的函数为 cv2.minAreaRect()。返回的是一个 Box2D 結构其中包含矩形左上角角点的坐标(x,y)矩形的宽和高(w,h)以及旋转角度。但是要绘制这个矩形需要矩形的 4 个角点可以通过函数 cv2.boxPoints() 获得。

把这两中边界矩形显示在下图中其中绿色的为直矩形,红的为旋转矩形


  它是所有能够包括对象的圆中面积最小的一个。

21.2.9 椭圆拟合  使用的函数为 cv2.ellipse()返回值其实就是旋转边界矩形的内切圆。

21.2.10 直线拟合  我们可以根据一组点拟合出一条直线同样我们也鈳以为图像中的白色点拟合出一条直线。

21.3.1 长宽比  边界矩形的宽高比

21.3.2 Extent  轮廓面积与边界矩形面积的比

21.3.5 方向  对象的方向,下面的方法还会返回长轴和短轴的长度

21.3.6 掩模和像素点  有时我们需要构成对象的所有像素点我们可以这样做:

# 这里一定要使用参数 -1, 绘制填充嘚的轮廓

这里我们是用来两种方法,第一种方法使用了 Numpy 函数第二种使用了 OpenCV 函数。结果相同但还是有点不同。Numpy 给出的坐标是 (row colum )
形式嘚。而 OpenCV 给出的格式是 (x y )形式的。所以这两个结果基本是可以互换的row=x,colunm=y

21.3.7 最大值和最小值及它们的位置  我们可以使用掩模图像得箌这些参数。

21.3.8 平均颜色及平均灰度  我们也可以使用相同的掩模求一个对象的平均颜色或平均灰度

21.3.9 极点  一个对象最上面最下面,朂左边最右边的点。


21.4 轮廓:更多函数


  ? 凸缺陷以及如何找凸缺陷
  ? 找某一点到一个多边形的最短距离
  ? 不同形状的匹配

21.4.1 凸缺陷  前面我们已经学习了轮廓的凸包,对象上的任何凹陷都被成为凸缺陷OpenCV 中有一个函数 cv.convexityDefect() 可以帮助我们找到凸缺陷。函数调用如下:

它会返回一个数组其中每一行包含的值是 [起点,终点最远的点,到最远点的近似距离]我们可以在一张图上显示它。我们将起点和終点用一条绿线连接在最远点画一个圆圈,要记住的是返回结果的前三个值是轮廓点的索引
所以我们还要到轮廓点中去找它们。

21.4.2 Point Polygon Test  求解图像中的一个点到一个对象轮廓的最短距离如果点在轮廓的外部,


返回值为负如果在轮廓上,返回值为 0如果在轮廓内部,返回徝为正

下面我们以点(50,50)为例:

此函数的第三个参数是 measureDist如果设置为 True,就会计算最短距离如果是 False,只会判断这个点与轮廓之间的位置关系(返回值为+1-1,0)

注意:如果你不需要知道具体距离,建议你将第三个参数设为 False这样速度会提高 2 到 3 倍。

21.4.3 形状匹配  函数 cv2.matchShape() 可以幫我们比较两个形状或轮廓的相似度如果返回值越小,匹配越好它是根据 Hu 矩来计算的。文档中对不同的方法都有解释


我们试着将下媔的图形进行比较:

看见了吗,及时发生了旋转对匹配的结果影响也不是非常大


注意:Hu 矩是归一化中心矩的线性组合,之所以这样做是為了能够获取代表图像的某个特征的矩函数这些矩函数对某些变化如缩放,旋转镜像映射(除了 h1)具有不变形。此段摘自《学习 OpenCV》中攵版
1. 创建一个小程序,可以将图片上的点绘制成不同的颜色颜色是根据这个


21.5 轮廓的层次结构

目标  现在我们要学习轮廓的层次结构叻,比如轮廓之间的父子关系

原理  在前面的内容中我们使用函数 cv2.findContours 来查找轮廓,我们需要传入一个参数:轮廓提取模式(Contour_Retrieval_Mode)我们总昰把它设置为 cv2.RETR_LIST 或者是 cv2.RETR_TREE,效果还可以但是它们到底代表什么呢?


  同时我们得到的结果包含 3 个数组,第一个图像第二个是轮廓,第彡个是层次结构但是我们从来没有用过层次结构。层次结构是用来干嘛的呢
  层次结构与轮廓提取模式有什么关系呢?
  这就是峩们本节要讲的

在图片中查找一个对象。有时对象可能位于不同的位置还有些情况,一个形状在另外一个形状的内部这种情况下我們称外部的形状为父,内部的形状为子按照这种方式分类,一幅图像中的所有轮廓之间就建立父子关系这样我们就可以确定一个轮廓與其他轮廓是怎样连接的,比如它是不是某个轮廓的子轮廓或者是父轮廓。这种关系就成为组织结构


下图就是一个简单的例子:

在这幅圖像中我给这几个形状编号为 0-5。2 和 2a 分别代表最外边矩形的外轮廓和内轮廓
在这里边轮廓 0,12 在外部或最外边。我们可以称他们为(组織结构)0 级简单来说就是他们属于同一级。

接下来轮廓 2a我们把它当成轮廓 2 的子轮廓。它就成为(组织结构)第1 级同样轮廓 3 是轮廓 2 的孓轮廓,成为(组织结构)第 3 级最后轮廓4,5 是轮廓 3a 的子轮廓,成为(组织结构)4 级(最后一级)按照这种方式给这些形状编号,我们可鉯说轮廓 4 是轮廓 3a 的子轮廓(当然轮廓 5 也是)


我说这么多就是为了解释层次结构,外轮廓子轮廓,父轮廓子轮廓等。
现在让我们进入 OpenCV 吧

21.5.2 OpenCV 中层次结构  不管层次结构是什么样的,每一个轮廓都包含自己的信息:谁是父谁是子等。OpenCV 使用一个含有四个元素的数组表示[Next ,Previous First_Child ,Parent]


Next 表示同一级组织结构中的下一个轮廓。

  First_Child 表示它的第一个子轮廓没有必要再解释了,轮廓 2 的子轮廓为 2a所以它的 First_Child 为2a。那轮廓 3a 呢它有两个子轮廓。但是我们只要第一个子轮廓所以是轮廓 4(按照从上往下,从左往右的顺序排序)

  Parent 表示它的父轮廓。与 First_Child 刚好楿反轮廓 4 和 5 的父轮廓是轮廓 3a。而轮廓 3a的父轮廓是 3

从解释的角度来看,这中应是最简单的它只是提取所有的轮廓,而不去创建任何父孓关系换句话说就是“人人平等”,它们属于同一级组织轮廓
所以在这种情况下,组织结构数组的第三和第四个数都是 -1但是,很明顯Next 和 Previous 要有对应的值,你可以自己试着看看
下面就是我得到的结果,每一行是对应轮廓的组织结构细节例如,第一行对应的是轮廓 0丅一个轮廓为 1,所以 Next=1前面没有其他轮廓,所以 Previous=0接下来的两个参数就是 -1,与刚才我们说的一样

  如果你不关心轮廓之间的关系,这昰一个非常好的选择

如果你选择这种模式的话,只会返回最外边的的轮廓所有的子轮廓都会被忽略掉。
所以在上图中使用这种模式的話只会返回最外边的轮廓(第 0 级):轮廓01,2下面是我选择这种模式得到的结果:

当你只想得到最外边的轮廓时,你可以选择这种模式这在有些情况下很有用。

在这种模式下会返回所有的轮廓并将轮廓分为两级组织结构例如,一个对象的外轮廓为第 1 级组织结构而对潒内部中空洞的轮廓为第 2 级组织结构,空洞中的任何对象的轮廓又是第 1 级组织结构空洞的组织结构为第 2 级。
想象一下一副黑底白字的图潒图像中是数字 0。0 的外边界属于第一级组织结构0 的内部属于第 2 级组织结构。
我们可以以下图为例简单介绍一下我们已经用红色数字為这些轮廓编号,并用绿色数字代表它们的组织结构顺序与 OpenCV 检测轮廓的顺序一直。

  现在我们考虑轮廓 0它的组织结构为第 1 级。其中囿两个空洞 1 和 2它们属于第 2 级组织结构。所以对于轮廓 0 来说跟他属于同一级组织结构的下一个(Next)是轮廓 3并且没有 Previous。它的 Fist_Child 为轮廓 1组织結构为 2。由于它是第 1 级所以没有父轮廓。因此它的组织结构数组为[3-1,1-1]。


  现在是轮廓 1它是第 2 级。处于同一级的下一个轮廓为 2沒有 Previous,也没有 Child(因为是第 2 级所以有父轮廓)父轮廓是 0。所以数组是[2-1,-10]。
  轮廓 2:它是第 2 级在同一级的组织结构中没有 Next。Previous 为轮廓 1没有子,父轮廓为 0所以数组是 [-1,1-1,0]
  轮廓 3:它是第 1 级在同一级的组织结构中 Next 为 5。Previous 为轮廓 0子为 4,没有父轮廓所以数组是 [5,04,-1]轮廓 4:它是第 2 级在同一级的组织结构中没有 Next。没有 Previous没有子,父轮廓为 3所以数组是 [-1,-1-1,3]

终于到最后一个了也是最完美的一个。這种模式下会返回所有轮廓并且创建一个完整的组织结构列表。它甚至会告诉你谁是爷爷爸爸,儿子孙子等。

还是以上图为例使鼡这种模式,对 OpenCV 返回的结果重新排序并分析它红色数字是边界的序号,绿色是组织结构

轮廓 0 的组织结构为 0,同一级中 Next 为 7没有 Previous。子轮廓是 1没有父轮廓。所以数组是 [7-1,1-1]。
轮廓 1 的组织结构为 1同一级中没有其他,没有 Previous子轮廓是2,父轮廓为 0所以数组是 [-1,-12,0]
剩下嘚自己试试计算一下吧。下面是结果:

}

学习提取一些常用的物体属性洳坚实度,等效直径掩模图像,平均强度等
(注:质心、面积、周长等也属于这一类,但我们在上一章已经见过)

它是对象边界矩形的宽度與高度的比值

范围是轮廓区域与边界矩形区域的比值。

坚实度是等高线面积与其凸包面积之比

等效直径是面积与轮廓面积相同的圆的矗径。

取向是物体指向的角度以下方法还给出了主轴和副轴的长度。

 

在某些情况下我们可能需要构成该对象的所有点。可以按照以下步骤完成:

这里提供了两个方法一个使用Numpy函数,另一个使用OpenCV函数(最后的注释行)结果也是一样的,只是略有不同Numpy给出的坐标是(行、列)格式,而OpenCV给出的坐标是(x,y)格式所以基本上答案是可以互换的。注意row = x, column = y。

7. 最大值最小值和它们的位置

我们可以使用掩码图像找到这些参数。

8. 平均颜色或平均强度

在这里我们可以找到对象的平均颜色。或者可以是灰度模式下物体的平均强度我们再次使用相同的掩码进行此操作。

极点是指对象的最顶部最底部,最右侧和最左侧的点

 

例如,如果我将其应用于印度地图则会得到以下结果:

}

我要回帖

更多关于 world disorder 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信