python轮廓函数 python 轮廓检测

OpenCV-Python教程:22.轮廓层级

理论

成都创新互联公司坚持“要么做到,要么别承诺”的工作理念,服务领域包括:网站建设、成都做网站、企业官网、英文网站、手机端网站、网站推广等服务,满足客户于互联网时代的桂阳网站设计、移动媒体设计的需求,帮助企业找到有效的互联网解决方案。努力成为您成熟可靠的网络建设合作伙伴!

在前面的关于轮廓的几节里,我们介绍了轮廓相关的一些函数。但当我们用cv2.findContours()函数来找轮廓的时候,我们传入了一个参数,Contour Retrieval Mode。我们一般传的是cv2.RETR_LIST或者cv2.RETR_TREE这样就可以了。但是这个参数实际是什么意思呢?

并且在输出时我们得到了三个数组,第一个是图像,第二个是我们的轮廓,第三个输出名字是hierarchy。但是我们一直没用这个。

什么是层级?

一般来说我们用cv2.findContours()函数来检测图像里的目标,有时候目标在不同的地方,但是在有些情况下,有些图形在别的图形里面,就像图形嵌套,在这种情况下,我们把外面那层图形叫做parent,里面的叫child。这样图形里的轮廓之间就有了关系。我们可以指定一个轮廓和其他之间的是如何连接的,这种关系就是层级。

看下面的例子:

在这个图像里,不同的图形我标注了0-5,2和2a表示了最外层盒子的外部和内部轮廓。

这里轮廓0,1,2是外部的。我们可以说他们是hierarchy-0,或者他们是同层级的。

接下来是contour-2a,可以认为是轮廓-2的孩子,或者反过来,contour-2是contour-2a的父亲,所以它在hierarchy-1里。类似的contour-3是contour-2的孩子,在下一层级。最后contour4,5是contour-3a的孩子,它们在最后的层级。

OpenCV里的层级表示

每个轮廓有他自己的关于层级的信息,谁是他的孩子,谁是他的父亲等。OpenCV用一个包含四个值得数组来表示:[Next, Previous, First_Child, Parent]

"Next表明同一层级的下一个轮廓"

比如,在我们的图片里的contour-0,水上hi他相同层级的下一个轮廓?是contour-1,所以Next=1,对于Contour-1,下一个是contour-2,所以Next=2

那对于contour-2呢?没有同层级的下一个轮廓,所以Next=-1。那么对于contour-4呢?同层级的下一个是contour-5,所以下一个轮廓是contour-5.Next=5

"Previous指同层级的前一个轮廓"

和上面一样,contour-1的前一个是contour-0.contour-2的前一个contour-1.对于contour-0没有前序,所以-1

"First_Child指它的第一个孩子轮廓"

不用解释,对于contour-2,孩子是contour-2a,所以这里是contour-2a的索引,contour-3a有两个孩子,但我们只取第一个,是contour-4,所以First_Child=4.

"Parent指它的父轮廓索引"

和First_Child相反,contour-4和contour-5的parent都是contour-3a,对于contour-3a,是contour-3

注意:

如果没有孩子或者父亲,就为-1

我们知道了层级,现在来看OpenCV里的轮廓获取模式,四个标志cv2.RETR_LIST, cv2.RETR_TREE, cv2.RETR_CCOMP, cv2.RETR_EXTERNAL表示啥?

轮廓获取模式

1.RETR_LIST

这是最简单的一个,它获取所有轮廓,但是不建立父子关系,他们都是一个层级。

所以,层级属性第三个和第四个字段(父子)都是-1,但是Next和Previous还是有对应值。

下面是结果,每行是对应轮廓的层级信息。

hierarchy

2.RETR_EXTERNAL

如果用这个模式,它返回最外层的。所有孩子轮廓都不要,我们可以说在这种情况下,只有家族里最老的会被照顾,其他都不管。

所以在我们的图像里,有多少最外层的轮廓呢,有3个,contours 0,1,2

3.RETR_CCOMP

这个模式获取所有轮廓并且把他们组织到一个2层结构里,对象的轮廓外边界在等级1里,轮廓内沿(如果有的话)放在层级2里。如果别的对象在它里面,里面的对象轮廓还是放在层级1里,它的内沿在层级2.

看下面的例子,轮廓的顺序为红色,他们的层级是绿色,

看第一个轮廓,contour-0,他的层级是1,他有两个洞,contours1和2,他们都属于层级2,所以对于contour-0,Next是contour-3,没有前序,他的第一个孩子是contour-1,没有parent,所以层级数组是[3,-1,1,-1]

看contour-1,他在层级2里,Next是contour-2,没有前序,没有孩子,parent是contour-0,所以数组是[2,-1,-1,0]

同样对于contour-2,也在层级2里,没有next,前序是contour-1,没有孩子,parent是contour-0,所以[-1,1,-1,0]。

contour-3:next是contour-5,Previous是contour-0,Child是contour-4,没有parent,所以[5,0,4,-1]

contour-4:在层级2里,没有兄弟,所以没有Next,没有Previous,没有孩子,parent是contour-3,[-1,-1,-1,3]

4.RETR_TREE

最后,Mr.Perfect。它取回所有的轮廓并且创建完整的家族层级列表,它甚至能告诉你谁是祖父,父亲,儿子,孙子。。

比如把上面的图形用cv2.RETR_TREE,

对于contour-0:层级是0,Next是contour-7,没有previous,孩子是contour-1,没有parent,所以[7,-1,1,-1]

contour-1:在层级1里,没有同级的其他轮廓,没有previous,孩子是contour-2,所以[-1,-1,2,0]

OpenCV里的直方图

OpenCV-Python教程:19.轮廓属性

1图像矩

帮你计算一些属性,比如重心,面积等。

函数cv2.moments()会给你一个字典,包含所有矩值

你可以从这个里面得到有用的数据比如面积,重心等。重心可以用下面的式子得到:

2.轮廓面积

轮廓面积由函数cv2.contourArea()得到或者从矩里得到M['m00']

3.轮廓周长

可以用cv2.arcLength()函数得到。第二个参数指定形状是否是闭合的轮廓(如果传True)。或者只是一个曲线。

4.轮廓近似

这会把轮廓形状近似成别的边数少的形状,边数由我们指定的精确度决定。这是Douglas-Peucker算法的实现。

要理解这个,假设你试图找一个图像里的方块,但是由于图像里的一些问题,你得不到一个完美的方块,只能得到一个“坏方块”。现在你可以使用这个函数来近似,第二个参数叫epsilon,是从轮廓到近似轮廓的最大距离。是一个准确率参数,好的epsilon的选择可以得到正确的输出。

在下面第二个图像里,绿线显示了epsilon = 10% of arc length 的近似曲线。第三个图像显示了epsilon = 1% of the arc length。第三个参数指定曲线是否闭合。

5.凸形外壳

凸形外壳和轮廓近似类似,但是还不一样(某些情况下两个甚至提供了同样的结果)。这儿,cv2.convexHull()函数检查凸面曲线缺陷并修复它。一般来说,凸面曲线总是外凸的,至少是平的,如果它内凹了,这就叫凸面缺陷。比如下面这张图,红线显示了手的凸形外壳。双向箭头显示了凸面缺陷,是轮廓外壳的最大偏差。

参数详情:

·points 是我们传入的轮廓

·hull 是输出,一般我们不用传

·clockwise: 方向标示,如果是True,输出凸形外壳是顺时针方向的。否则,是逆时针的。

·returnPoints:默认是True。然后会返回外壳的点的坐标。如果为False,它会返回轮廓对应外壳点的索引。

所以要获得凸形外壳,下面

但是如果你想找到凸面缺陷,你需要传入returnPoints = False。我们拿上面的矩形图形来说,首先我找到他的轮廓cnt,现在用returnPoints = True来找他的凸形外壳,我得到下面的值:[[[234 202]], [[51 202]], [51 79]], [[234 79]]]  是四个角的点。如果你用returnPoints = False,我会得到下面的结果:[[129], [67], [0], [142]].  这是轮廓里对应点的索引,比如cnt[129] = [234, 202]],这和前面结果一样。

6.检查凸面

有一个函数用来检查是否曲线是凸面, cv2.isContourConvex().它返回True或False。

7.边界矩形

有两种边界矩形

7.a.正边界矩形

这个矩形不考虑对象的旋转,所以边界矩形的面积不是最小的,函数是cv2.boundingRect()。

假设矩形左上角的坐标是(x,y), (w, h)是它的宽和高

7.b.渲染矩形

这个边界矩形是用最小面积画出来的,所以要考虑旋转。函数是cv2.minAreaRect()。它返回一个Box2D结构,包含了(左上角(x,y),(width, height),旋转角度)。但是要画这个矩形我们需要4个角。这四个角用函数cv2.boxPoints()得到

8.最小闭包圆

我们找一个目标的外接圆可以用函数cv2.minEnclosingCircle().这个圆用最小面积完全包围目标。

9.椭圆

用一个椭圆来匹配目标。它返回一个旋转了的矩形的内接椭圆

10. 直线

类似的我们可以匹配一根直线,下面的图像包含一系列的白色点,我们可以给它一条近似的直线。

END

3.8 等高线

等高线可以简单地解释为连接所有连续点(沿着边界)的曲线,具有相同的颜色或强度。等高线是形状分析、目标检测和识别的有用工具。

让我们看看如何找到二值图像的轮廓:

cv2.findcontours() 函数中有三个参数,

第一个是源图像

第二个是轮廓检索模式

第三个是轮廓近似方法

它输出图像、轮廓和层次。轮廓是图像中所有轮廓的python列表。每个轮廓都是对象边界点(x,y)坐标的numpy数组。

使用 cv2.drawContours, 它也可以用来绘制任何给出边界点的形状。它的第一个参数是源图像,第二个参数是应该作为等高线列表,第三个参数是等高线索引(在绘制个体轮廓时使用)。要绘制所有轮廓,传递-1)、颜色、厚度等。

要绘制图像中的所有轮廓:

要绘制第4个轮廓:

但大多数情况下,下面的方法更适合:

这是 cv2.findContours 函数中的第三个参数的说明。

如果传递 cv2.CHAIN_APPROX_NONE,则存储所有边界点。但实际上我们需要所有的要点吗?例如,你发现了一条直线的轮廓。你需要这条线上所有的点来代表这条线吗?不,我们只需要这条线的两个端点。这就是 cv2.CHAIN_APPROX_SIMPLE所做的。它删除所有冗余点并压缩轮廓,从而节省内存。

你可以提取有用的数据,如面积、质心等。质心可以通过下面的方式来获取

它将一个轮廓形状近似为另一个形状,根据我们指定的精度,顶点数量较少。

为了理解这一点,假设您试图在图像中找到一个正方形,但是由于图像中的一些问题,您没有得到一个完美的正方形,而是一个“坏形状”(如下面第一幅图像所示)。现在可以使用此函数来近似形状。在这里,第二个参数称为epsilon,它是从轮廓到近似轮廓的最大距离。这是一个精度参数。为了得到正确的输出,需要明智地选择epsilon。

下图,在第二幅图像中,绿线显示了epsilon=10%弧长的近似曲线。第三张图片显示的epsilon=弧长的1%相同。第三个参数指定曲线是否关闭。

凸面船体看起来类似于轮廓近似,但事实并非如此(在某些情况下两者都可能提供相同的结果)。在这里,cv2.converxHull()函数检查曲线是否存在凸性缺陷,并对其进行修正。一般来说,凸曲线是指总是凸出的曲线,或者至少是平的曲线。如果它在内部膨胀,就称为凸性缺陷。例如,检查下面的手图像。红线表示手的凸面外壳。双面箭头标记显示了凸性缺陷,即船体与轮廓的局部最大偏差。

points 是我们经过的轮廓。

hull 是输出,通常我们避免它。

clockwise :方向标志。如果为真,则输出凸壳为顺时针方向。否则,它是逆时针方向的。

returnPoints :默认为真。然后返回船体点的坐标。如果为false,则返回与外壳点对应的轮廓点索引。

因此,如上图所示,要得到一个凸面外壳,以下就足够了:

有一个函数可以检查曲线是否是凸的,cv2.isContourConvex()。它只是返回正确还是错误。

直的矩形,不考虑物体的旋转。所以边界矩形的面积不会是最小的。它由函数 cv2.boundingrect() 找到。

设(x,y)为矩形的左上角坐标,(w,h)为矩形的宽度和高度。

在这里,边界矩形是用最小面积绘制的,因此它也考虑了旋转。使用的函数是 cv2.minareect() 。但是要画这个矩形,我们需要四个角。它是通过函数 cv2.boxpoints() 获得的。

在这里,我们将学习提取一些经常使用的对象属性,如坚固性、等效直径、遮罩图像、平均强度等。

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

坚固性是指轮廓面积与其凸面外壳面积之比。

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

方向是指向对象的角度。下面的方法也给出了长轴和短轴的长度。

在某些情况下,我们可能需要包含该对象的所有点。可以这样做:

这里,有两种方法,一种是使用numpy函数,另一种是使用opencv函数(最后一行注释)。结果也相同,但有轻微的差异。numpy以(行、列)格式给出坐标,而opencv以(x、y)格式给出坐标。所以基本上答案会互换。注意,row=x,column=y。

极端点是指物体的最上面、最下面、最右边和最左边的点。

【python】opencv库中cv2.findContours()和cv2.drawContours()函数

一.查找轮廓

cv2.findContours()

[image,] contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

轮廓检索方式:

轮廓近似方法:

二.绘制轮廓

cv2.drawContours()

cv2.drawContours(img, contours, -1, (0, 0, 255), 2) 

从图像边缘到物体轮廓

上一篇已经讲解了很多算子用来检测边缘,其中用得最多的是canny边缘检测。只有边缘还不够,有很多时候我们还需要获得图片上的某物体轮廓。

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

Opencv提供了一个函数findContours()用于发现轮廓,它有三个参数,第一个是输入图像,第二个是轮廓检索模式,第三个是轮廓近似方法。

findContours()的返回值有三个,第一个是图像,第二个是轮廓,第三个是(轮廓的)层析结构。最常用的是第二个返回值。

轮廓(第二个返回值)是一个Python列表,其中储存这图像中所有轮廓。每一个轮廓都是一个Numpy数组,包含对象边界点(x,y)的坐标。

Opencv提供了一个函数drawContours()用于绘制轮廓。

轮廓特征计算的结果并不等同于像素点的个数,而是根据几何方法算出来的,所以有小数。

参数2表示轮廓是否封闭

形状的外接矩形有两种,如下图,绿色的叫外接矩形,表示不考虑旋转并且能包含整个轮廓的矩形。蓝色的叫最小外接矩,考虑了旋转。

其中np.int0(x)是把x取整的操作,比如377.93就会变成377,也可以用x.astype(np.int)

外接圆跟外接矩形一样,找到一个能包围物体的最小圆:

我们可以用得到的轮廓拟合出一个椭圆:

第一个参数是某一轮廓。第二个参数是像素点坐标。第三个参数如果为True则输出该像素点到轮廓最近距离;如果为False,则输出为正表示在轮廓内,0为轮廓上,负为轮廓外。


分享文章:python轮廓函数 python 轮廓检测
分享链接:http://myzitong.com/article/dodjohe.html