OpenCV中的图像处理4

OpenCV中的轮廓

什么是轮廓

轮廓可以简单的解释为连接具有相同颜色或强度的所有连续点(沿边界)的曲线。轮廓是用于形状分析以及对象检测和识别的有用工具。

  • 为了获得更高的准确性,请使用二进制图像。在找到轮廓之前,应用阈值或canny边缘检测。
  • 从OpenCV3.2开始,cv.findContours()不再修改源图像。
  • 在OpenCV中,找到轮廓就像从黑色背景中找到白色物体。要找到的对象应该是白色,背景应该是黑色。
    下面代码展示如何找到二进制图像(也称二值图像,通常用一个二维数组描述,1位非0即1的数表示一个像素,通常0表示黑色,1表示白色)的轮廓:
import cv2 as cv
import numpy as np

img = cv.imread('./OpenCV/fusi1.jpg')
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
ret, thresh = cv.threshold(gray, 127, 255, 0)
contours, hierarchy = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)

cv.findcontour()函数中有三个参数,第一个是源图像需为二值图,即黑白的(不是灰度图),可将读取的图像先转成灰度的,再转成二值图;第二个是轮廓检索模式,cv.RETR_EXTERNAL只检测外轮廓,cv.RETR_LIST检测的轮廓不建立等级关系,cv.RETR_CCOMP建立两个等级的轮廓,上一层为外边界,内层为内孔的边界,如果内孔内还有连通物体,则这个物体的边界也在顶层,cv.RETR_TREE建立一个等级树结构的轮廓;第三个是轮廓逼近方法cv.CHAIN_APPROX_NOME存储所有的轮廓点,相邻的两个点的像素位置差不超过,cv.CHAIN_APPROX_SIMPLE压缩水平方向、垂直方向、对角线方向的元素,只保留该方向的终点坐标。输出等高线和层次结构,轮廓是图像中所有轮廓的Python列表,每个单独的轮廓是一个(x, y)坐标的Numpy数组的边界点的对象。

如何绘制轮廓?

使用cv.drawContours()函数绘制轮廓,只要有边界点,它也可以用来绘制任何形状。它的第一个参数是源图像,第二个参数是作为Python列表传递的轮廓,第三个参数是轮廓的索引(绘制单个轮廓时有用,要绘制所有轮廓,传递-1),其余参数是颜色、厚度等等

  • 在图像中绘制所有轮廓:cv.drawContours(img, contours, -1, (0, 255, 0), 3)
  • 绘制单个轮廓,如第四个轮廓:cv.drawContours(img, contours, 3, (0, 255, 0), 3
  • 绘制单个轮廓的另一个方法,大多数情况下以下方法很有用:
    cnt = contours[4
    cv.drawContours(img, [cnt], 0, (0, 255, 0), 3

轮廓近似方法

这是cv.drawContours()函数中的第三个参数。
如果参数传递的是cv.CHAIN_APPROX_NODE,则轮廓存储所有边界点的(x, y)坐标。传递cv.CHAIN_APPROX_SIMPLE会删除所有冗余点并压缩轮廓,从而节省内存。
下面为使用两种轮廓近似方法展示图像轮廓的代码:

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt

img = cv.imread('./OpenCV/dark.png')
pimg = cv.cvtColor(img, cv.COLOR_BGR2RGB)
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)  # 转换为灰度图
ret, thresh = cv.threshold(gray, 127, 255, cv.THRESH_BINARY)    # 二值化灰度图
contours1, hierarchy = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
contours2, hierarchy2 = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_NONE)
draw_simple = pimg.copy()
draw = pimg.copy()
dgray_simple = cv.merge((thresh.copy(), thresh.copy(), thresh.copy()))
dgray = cv.merge((thresh.copy(), thresh.copy(), thresh.copy()))
res1 = cv.drawContours(draw_simple, contours1, -1, (255, 0, 0), 2)
res2 = cv.drawContours(draw, contours2, -1, (255, 0, 0), 2)
res3 = cv.drawContours(dgray_simple, contours1, -1, (255, 0, 0), 2)
res4 = cv.drawContours(dgray, contours2, -1, (255, 0, 0), 2)
images = [pimg, res1, res2, res3, res4]
titles = ['Original', 'Simple__outline', 'All_outline', 'Gray_Simple', 'Gray_All']
for i in range(5):
    plt.subplot(2, 3, i + 1)
    plt.imshow(images[i]), plt.title(titles[i])
    plt.xticks([]), plt.yticks([])
plt.show()

在这里插入图片描述
在二值化(或灰度)图像中是无法使用其他颜色画出图像轮廓,因为图像是单通道的,若要展示,可将三幅二值化(或灰度)图进行堆叠。

轮廓特征

1. 特征矩

特征矩可帮助计算一些特征,如物体的质心、面积等。函数cv.moment()提供了所有计算出的矩值的字典,如下代码:

import cv2 as cv
import numpy as np

img = cv.imread('./OpenCV/hand.png')
ret, thresh = cv.threshold(cv.cvtColor(img, cv.COLOR_BGR2GRAY), 127, 255, 0)
contours, hierachy = cv.findContours(thresh, 1, 2)
cnt = contours[0]
M = cv.moments(cnt)
print(M)

结果:
{‘m00’: 25055.0, ‘m10’: 4036943.333333333, ‘m01’: 4082197.0, ‘m20’: 702954431.1666666,
‘m11’: 654563694.75, ‘m02’: 745633429.5, ‘m30’: 129617766948.20001, ‘m21’: 113234562831.3, ‘m12’: 119268551752.56667, ‘m03’: 146615303293.9, ‘mu20’: 52508952.15870643, ‘mu11’: -3173202.655840397, ‘mu02’: 80523377.74150872, ‘mu30’: -565371477.2726593, ‘mu21’: -274852113.0884037, ‘mu12’: 163677451.77373505, ‘mu03’: -1109587190.9181519, ‘nu20’: 0.08364587675018598, ‘nu11’: -0.00505485840683985, ‘nu02’: 0.1282723850538334, ‘nu30’: -0.005689811478185491, ‘nu21’: -0.0027660693379827884, ‘nu12’: 0.0016472246677793024, ‘nu03’: -0.011166714609285085}
可使用M提取出有用的数据。如质心由以下式子计算: C x = M 10 M 00 C_{x}=\dfrac{M_{10}}{M_{00}} Cx=M00M10 C y = M 01 M 00 C_{y}=\dfrac{M_{01}}{M_{00}} Cy=M00M01,代码表示如下:

cx = int(M['m10']/M['m00'])
cy = int(M['m01']/M['m00'])

2. 轮廓面积

由函数cv.contourArea()M['m00']得到

area = cv.contourArea(cnt)

3. 轮廓周长

也称弧长,可使用函数cv.arcLength()得到,其第二个参数用来指定形状是闭合轮廓(True)还是曲线(False)

perimeter = cv.arcLength(cnt, True)

4. 轮廓近似

使用函数cv.approxPolyDP(),根据指定的精度,将轮廓形状近似为顶点数量较少的其他形状,是Douglas-Peucker算法的实现。假设试图在图像中找到一个正方形,但由于图像中得某些问题,没有得到一个完美的正方形,可使用此功能来近似形状。在这种情况下,第二个参数称为epsilon,它是从轮廓到近似轮廓的最大距离,是一个精度参数。正确选择epsilon才能获得正确的输出。

epsilon = 0.1 * cv.arcLength(cnt, True)
approx = cv.approxPolyDP(cnt, epsilon, True)

5. 轮廓凸包

凸包外观看起来与轮廓逼近相似,但不相似(在某些情况下两者可能提供相同的结果)。函数cv.convexHull()检查曲线是否存在凸凹缺陷并对其进行校正;一般而言,凸曲线是始终凸出或至少平坦的曲线;如果在内部凸出,则称为凸度缺陷;

hull = cv.convexHull(points[, hull[, clockwise[, returnPoints]]])

其中点是传递到的轮廓;凸包是输出,通常忽略它;顺时针方向:方向标记,若为True,则输出凸包为顺时针方向,False为逆时针;returnPoints:默认情况下为True,返回凸包的坐标,False则返回与凸包点相对应的轮廓点的索引,可使用cnt[索引]获取对应凸度缺陷。
要获取整个图像的凸包,可使用:

hull = cv.convexHull(cnt)

6. 检查凸度

函数cv.isContourConvex()具有检查曲线是否凸出的功能,凸出返回True,否则返回False。

k = cv.isContourConvex(cnt)

7. 边界矩形

1. 直角矩形

它是一个矩形,不考虑物体的旋转,所以这种边界矩形的面积不是最小的,由函数cv.boundingRect()得到。令(x, y)为矩形的左上角坐标,而(w, h)为矩形的宽度和高度。

x, y, w, h = cv.boundingRect(cnt)
cv.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)

2. 旋转矩形

这种边界矩形是用最小面积绘制的,考虑了旋转。使用函数cv.minAreaRect();返回一个Box2D结构,其中包含中心(x, y),(宽度, 高度),旋转角度;要画出这个矩形,需要矩形的四个角,由函数cv.boxPoints()获得。

rect = cv.minAreaRect(cnt)
box = cv.boxPoints(rect)
box = np.int0(box)
cv.drawContours(img, [box], 0, (0, 0, 255), 2)

8. 最小闭合圈

使用函数cv.minEnclosingCircle()查找对象的圆周,它是一个以最小面积完全覆盖物体的圆。

(x, y), radius =cv.minEnclosingCircle(cnt)
center = (int(x), int(y))
radius = int(radius)
cv.circle(img, center, radius, (0, 255, 0), 2)

9. 拟合一个椭圆

把一个椭圆拟合到一个物体上,返回内接椭圆的旋转矩形。

ellipse = cv.fitEllipse(cnt)
cv.ellipse(img, ellipse, (0, 255, 0), 2)

10. 拟合直线

可以将一条直线拟合到一组点,可以将下面包含的一组白点,近似一条直线。

rows, cols = img.shape[:2]
[vx, vy, x, y] = cv.fitLine(cnt, cv.DIST_L2, 0, 0.01, 0.01)
lefty = int((-x * vy / vx) + y)
righty = int(((cols - x) * vy / vx) + y)
cv.line(img, (cols - 1, rignty), (0, lefty), (0, 255, 0), 2)

各轮廓特征完整展示代码:

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt

img = cv.imread('./OpenCV/hand.png')
ret, thresh = cv.threshold(cv.cvtColor(img, cv.COLOR_BGR2GRAY), 127, 255, 0)
contours, hierachy = cv.findContours(thresh, 1, 2)
cnt = contours[0]
M = cv.moments(cnt)
cx = int(M['m10']/M['m00'])
cy = int(M['m01']/M['m00'])
area = cv.contourArea(cnt)
perimeter = cv.arcLength(cnt, True)
print('第一个轮廓质心为:({}, {}),面积为:{},周长为:{}'.format(cx, cy, area, perimeter))
epsilon = 0.1 * cv.arcLength(cnt, True)
approx = cv.approxPolyDP(cnt, epsilon, True)
draw_imgs = []
for i in range(8) :
    draw_imgs.append(cv.cvtColor(img.copy(), cv.COLOR_BGR2RGB))
approx_img = cv.drawContours(draw_imgs[1], [approx], -1, [255, 0, 0], 2)
hull = cv.convexHull(cnt)
hull_img = cv.drawContours(draw_imgs[2], [hull], -1, [0, 255, 0], 2)
k = cv.isContourConvex(hull)
print('图像轮廓是否有凸出?:{}'.format(k))
x, y, w, h = cv.boundingRect(cnt)
cv.rectangle(draw_imgs[3], (x, y), (x + w, y + h), (0, 255, 0), 2)
rect = cv.minAreaRect(cnt)
box = cv.boxPoints(rect)
box = np.int0(box)
cv.drawContours(draw_imgs[4], [box], 0, (0, 0, 255), 2)
(x, y), radius =cv.minEnclosingCircle(cnt)
center = (int(x), int(y))
radius = int(radius)
cv.circle(draw_imgs[5], center, radius, (0, 255, 0), 2)
ellipse = cv.fitEllipse(cnt)
cv.ellipse(draw_imgs[6], ellipse, (0, 255, 0), 2)
rows, cols = img.shape[:2]
[vx, vy, x, y] = cv.fitLine(cnt, cv.DIST_L2, 0, 0.01, 0.01)
lefty = int((-x * vy / vx) + y)
righty = int(((cols - x) * vy / vx) + y)
cv.line(draw_imgs[7], (cols - 1, righty), (0, lefty), (0, 255, 0), 2)
images = [draw_imgs[0], approx_img, hull_img, draw_imgs[3], draw_imgs[4], draw_imgs[5], draw_imgs[6], draw_imgs[7]]
titles = ['Original', 'Approx', 'Hull', 'Rect', 'RotateRect', 'MinEnclosingCircle', 'Ellipse', 'Line']
for i in range(8):
    plt.subplot(2, 4, i + 1)
    plt.imshow(images[i]), plt.title(titles[i])
    plt.xticks([]), plt.yticks([])
plt.show()

输出:

第一个轮廓质心为:(161, 162),面积为:25058.0,周长为:1281.484406709671
图像轮廓是否有凸出?:True

在这里插入图片描述

轮廓属性

学习提取一些常用的物体属性,如坚实度,等效直径,掩模图像,平均强度等(上节的质心、面积、周长等也属于这一类)。

1. 长宽比

它是对象边界矩形的宽度与高度的比值。 A s p e c t R a t i o = W i d t h H e i g h t Aspect Ratio=\dfrac{Width}{Height} AspectRatio=HeightWidth.

x, y, w, h = cv.boundingRect(cnt)
aspect_ratio = float(w) / h

2. 范围

范围是轮廓区域与边界区域的比值。
E x t e n t = O b j e c t A r e a B o u n d i n g R e c t a n g l e A r e a Extent=\dfrac{Object Area}{Bounding Rectangle Area} Extent=BoundingRectangleAreaObjectArea

area = cv.contourArea(cnt)
x, y, w, h = cv.boundingRect(cnt)
rect_area = w * h
extent = float(area) / rect_area

3. 坚实度

坚实度是等高线面积与其凸包面积之比。
S o l i d i t y = C o n t o u r A r e a C o n v e x H u l l A r e a Solidity=\dfrac{Contour Area}{Convex Hull Area} Solidity=ConvexHullAreaContourArea

area = cv.contourArea(cnt)
hull = cv.convexHull(cnt)
hull_area = cv.contourArea(hull)
solidity = float(area) / hull_area

4. 等效直径

等效直径是面积与轮廓面积相同的圆的直径。
E q u i v a l e n t D i a m e t e r = 4 × C o n t o u r A r e a π Equivalent Diameter = \sqrt{\dfrac{4\times Contour Area}{\pi}} EquivalentDiameter=π4×ContourArea

area = cv.contourArea(cnt)
equi_diameter = np.sqrt(4 * area / np.pi)

5. 取向

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

(x, y), (MA, ma), angle = cv.fitEllipse(cnt)

6. 掩码和像素点

获得构成该对象的所有点

mask = np.zeros(imgray.shape, np.uint8)
cv.drawContours(mask, [cnt], 0, 255, -1)
npixelpoints = np.transpose(np.nonzero(mask))	# numpy函数
pixelpoints = cv.findNonZero(mask)	#OpenCV函数

适用numpy给出的坐标是(行, 列)格式,而使用OpenCV给出的坐标是(x, y)格式,注意row = x, column = y。

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

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

min_val, max_val, min_loc, max_loc = cv.minMaxLoc(imgray, mask=mask)

8. 平均颜色或平均强度

可以找到对象的平均颜色或灰度模式下的平均强度。

mean_val = cv.mean(img, mask=mask)

9. 极端点

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

leftmost = tuple(cnt[cnt[:, :, 0].argmin()][0])
rightmost = tuple(cnt[cnt[:, :, 0].argmax()][0])
topmost = tuple(cnt[cnt[:, :, 1].argmin()][0])
topmost = tuple(cnt[cnt[:, :, 1].argamx()][0])

10. 凸性缺陷

从凸包上的任何偏差都可以被认为是凸性缺陷,可使用函数cv.convexityDefects()找到。

hull = cv.convexHull(cnt, returnPoints=False)
defects = cv.convexityDefects(cnt, hull)

注意:需在发现凸包时,传递returnPoints=False,以找到凸性缺陷。
它返回一个数组,其中每行包含这些值-[起点、终点、最远点、到最远点的近似距离];可以用图像把它形象化,可以画一条连接起点和终点的线,然后在最远处画一个圆;返回的前三个值是cnt的索引,所以得从cnt中获取这些值。

11. 点多边形测试

函数cv.pointPolygonTest()可获得图像中一点到轮廓线的最短距离;点在轮廓线外时距离为负,在轮廓线内时为正,在轮廓线上时为零。
如检查点(50, 50):

dist = cv.pointPolygonTest(cnt, (50, 50), True)

第三个参数是measureDist,值为True时,函数返回有符号的距离;为False时,则查找该点是在轮廓线内部(函数返回1)、外部(返回-1)、之上(返回0)。找距离是一个耗时的过程,若不想找到此距离,将第三个参数设置为False可使速度提高2-3倍。

12. 形状匹配

函数cv.matchShapes()可以比较两个形状或两个轮廓,并返回一个显示相似性的度量;结果越低,匹配越好,它是根据矩值计算出来的。

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt

img = cv.imread('./OpenCV/hand.png')
rimg = cv.imread('./OpenCV/rhand.png')
limg = cv.imread('./OpenCV/lozenge.png')
ret, thresh = cv.threshold(cv.cvtColor(img, cv.COLOR_BGR2GRAY), 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)
# 获取结构元素
k = cv.getStructuringElement(cv.MORPH_RECT, (3, 3))
# 开操作
thresh = cv.morphologyEx(thresh, cv.MORPH_OPEN, k)
contours, hierachy = cv.findContours(thresh, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
# 在原图上绘制轮廓,以方便和凸包对比,发现凸缺陷
cv.drawContours(img, contours, -1, (0, 225, 0), 2)
pimg = img.copy()
cnt = contours[0]
for c in range(len(contours)):
    # 是否为凸包
    ret = cv.isContourConvex(contours[c])
    if ret:
        cnt = contours[c]
        break
hull = cv.convexHull(cnt, returnPoints=False)
defects = cv.convexityDefects(cnt, hull)
for i in range(defects.shape[0]):
    s, e, f, d = defects[i, 0]
    start = tuple(cnt[s][0])
    end = tuple(cnt[e][0])
    far = tuple(cnt[f][0])
    cv.line(img, start, end, (255, 255, 0), 2)
    cv.circle(img, far, 3, (0, 0, 255), -1)
# 检查点(50, 50)与轮廓的距离或关系
dist = cv.pointPolygonTest(cnt, (50, 50), True)
print('点(50, 50)与轮廓的距离是:', dist)
ison = cv.pointPolygonTest(cnt, (50, 50), False)
if ison == 1:
    print('点(50, 50)在轮廓内部')
elif ison == -1:
    print('点(50, 50)在轮廓外部')
else:
    print('点(50, 50)在轮廓上')
ret, rthresh = cv.threshold(cv.cvtColor(rimg, cv.COLOR_BGR2GRAY), 127, 255, 0)
ret, lthresh = cv.threshold(cv.cvtColor(limg, cv.COLOR_BGR2GRAY), 127, 255, 0)
rcontours,hierarchy = cv.findContours(rthresh, 2, 1)
cv.drawContours(rimg, rcontours, -1, (0, 225, 0), 2)
rcnt = rcontours[0]
lcontours,hierarchy = cv.findContours(lthresh, 2, 1)
cv.drawContours(limg, lcontours, -1, (0, 225, 0), 2)
lcnt = lcontours[0]
ret1 = cv.matchShapes(cnt,rcnt,1,0.0)
ret2 = cv.matchShapes(cnt,lcnt,1,0.0)
ret3 = cv.matchShapes(cnt,cnt,1,0.0)
print('pimg与rimg相似性度量为:', ret1)
print('pimg与limg相似性度量为:', ret2)
print('pimg与自身相似性度量为:', ret3)
images = [img, pimg, rimg, limg]
titles = ['img', 'pimg', 'rimg', 'limg']
for i in range(4):
    plt.subplot(2, 2, i + 1)
    plt.imshow(cv.cvtColor(images[i], cv.COLOR_BGR2RGB)), plt.title(titles[i])
    plt.xticks([]), plt.yticks([])
plt.show()

在这里插入图片描述

(50, 50)与轮廓的距离是: -202.03960007879644
点(50, 50)在轮廓外部
pimg与rimg相似性度量为: 1.7976931348623157e+308
pimg与limg相似性度量为: 0.15376293094777732
pimg与自身相似性度量为: 0.0

轮廓分层

使用函数cv.findcontour()在图像中找到轮廓时,已经传递了一个参数,轮廓检索模式(通常使用cv.RETR_LISTcv.RETR_TREE),效果很好。

层次结构是什么

使用函数cv.findcontour()检测图像中的对象,有时对象在不同的位置;在某些情况下,某些形状在其他形状中,像嵌套的图形一样,在这种情况下,将外部的称为父类,内部的称为子类;这样,图像中的轮廓有了一定的相互关系,可以指定一个轮廓是如何相互连接的,比如,它是另一个轮廓的子轮廓,这种关系的表示称为层次结构。
下面是一个例子:
在这里插入图片描述
在这张图中,一些形状已经从0-5开始编号。2和2a分别表示最外层盒子的外部和内部轮廓。
这里,等高线0,1,2在外部或最外面。可以说,它们在层级-0中,或者简单地说,它们在同一个层级中。
其次是contour-2a。它可以被认为是contour-2的子级(或者反过来说contour-2是contour-2a的父级),contour-3是contour-2的子级。

OpenCV中的分级表示

每个轮廓都有它自己的信息关于它是什么层次,谁是它的孩子,谁是它的父母等等。OpenCV将它表示为一个包含四个值的数组:[Next, Previous, First_Child, Parent]
Next表示同一层次的下一个轮廓:
在图片中取contour-0,谁是下一个同级别的等高线?这是contour-1,令Next = 1;类似地取contour-1,下一个同级别的是contour-2,所以Next = 2;取contour-2呢?同一级别上没有下一条等高线,Next = -1。
Previous表示同一层次上的先前轮廓:
contour-1之前的等值线为同级别的contour-0;对于contour-0,没有前项,所以Previous设为-1。
First_Child表示它的第一个子轮廓:
对于contour-2, child是contour-2a,First_Child得到contour-2a对应的索引值;contour-3a有两个孩子,只关注第一个孩子。它是contour-4。
Parent表示其父轮廓的索引:
对于contour-3a,它的父轮廓是contour-3。

轮廓检索模式

1、RETR_LIST

它只是检索所有的轮廓,但不创建任何亲子关系。在这个规则下,父轮廓和子轮廓是平等的,它们只是轮廓,都属于同一层级。
因此,此种模式下,数组中[Next, Previous, First_Child, Parent]的第3和第4项总是-1。
若没有使用任何层次结构特性,此模式是使用的最佳选择。

2. RETR_EXTERNAL

使用此标志,它只返回极端外部标志。根据这项规则,每个家庭只有长子得到关注,不关心家庭的其他成员。在我们的图像中,有多少个极端的外轮廓?在等级0级?有3个,即等值线是0 1 2。
若只想提取外部轮廓,可以使用此标志。

3. RETR_CCOMP

此标志检索所有轮廓并将其排列为2级层次结构。物体的外部轮廓(即物体的边界)放在层次结构-1中。对象内部孔洞的轮廓(如果有)放在层次结构-2中。如果其中有任何对象,则其轮廓仅在层次结构1中重新放置。以及它在层级2中的漏洞等等。
只需考虑在黑色背景上的“白色的零”图像。零的外圆属于第一级,零的内圆属于第二级。
可以用一个简单的图像来解释它。用橙色标注了等高线的顺序;绿色标注了它们所属的层次,顺序与OpenCV检测等高线的顺序相同。
在这里插入图片描述
考虑第一个轮廓,即contour-0。这是hierarchy-1。它有两个孔,分别是等高线1和2,属于第二级。因此,对于轮廓-0,在同一层次的下一个轮廓是轮廓-3。previous也没有。在hierarchy-2中,它的第一个子结点是contour-1。它没有父类,因为它在hierarchy-1中。所以它的层次数组是[3,-1,1,-1]。
现在contour-1。它在层级-2中。相同层次结构中的下一个(在contour-1的父母关系下)是contour-2。没有previous。没有child,但是parent是contour-0。所以数组是[2,-1,-1,0]。
类似的contour-2:它在hierarchy-2中。在contour-0下,同一层次结构中没有下一个轮廓。所以没有Next。previous是contour-1。没有child,parent是contour0。所以数组是[-1,1,-1,0]。
contour-3:层次-1的下一个是轮廓-5。以前是contour-0。child是contour4,没有parent。所以数组是[5,0,4,-1]。
contour-4:它在contour-3下的层次结构2中,它没有兄弟姐妹。没有next,没有previous,没有child,parent是contour-3。所以数组是[-1,-1,-1,3]。

4. RETR_TREE

它检索所有的轮廓并创建一个完整的家族层次结构列表,谁是爷爷,父亲,儿子,孙子…
用橙色标注了等高线的顺序;绿色标注了它们所属的层次
在这里插入图片描述
取contour-0:它在hierarchy-0中。同一层次结构的next轮廓是轮廓-7。没有previous的轮廓。child是contour-1,没有parent。所以数组是[7,-1,1,-1]
以contour-2为例:它在hierarchy-1中。没有轮廓在同一水平。没有previous。child是contour-3。父母是contour-1。所以数组是[-1,-1,3,1]

学习来源:OpenCV-Python中文文档
参考:opencv学习—cv2.findContours()函数讲解(python)
OpenCV自学记录(5)——凸包检测和凸缺陷

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值