OpenCV 例程200篇 总目录-202205更新
【youcans 的 OpenCV 例程200篇】197.轮廓的基本特征
2. 轮廓的特征描述
在对实际图像进行轮廓查找时,得到的轮廓数量很多。获取轮廓后,通常基于轮廓的特征进行筛选、识别和处理。例如,基于轮廓的周长和面积对轮廓进行筛选,然后绘制筛选的目标轮廓或其最小外接矩形。
常用的轮廓特征,包括图像距、轮廓周长、轮廓近似、凸包、边界矩形、拟合图形等特征。
2.2 轮廓的面积、周长、质心和近似多边形
面积、周长、质心是常用的轮廓特征。
2.2.1 轮廓的面积
几何矩实质是面积或质量。函数 cv.moments() 的返回值 Moments[‘m00’] 表示轮廓面积。 轮廓的面积也可以使用函数 cv2.contourArea() 计算。
函数说明:
cv.contourArea(contour[, oriented] ) → retval
- contour:顶点构成的二维向量组(如轮廓列表 contours 中的一个轮廓)
- oriented:定向区域标志,默认值为 False,返回面积的绝对值,Ture 时则根据轮廓方向返回带符号的数值
2.2.2 轮廓的周长
轮廓的周长可以使用函数 cv2.arcLength() 计算。
函数说明:
cv.arcLength(curve, closed=True) → retval
- curve:以顶点构成的二维向量组表示的曲线(如轮廓列表 contours 中的一个轮廓)
- closed:曲线闭合标志,True 表示闭合曲线
2.2.3 轮廓的质心
轮廓的质心 (Cx,Cy) 可以通过一阶矩计算:
C
x
=
M
10
/
M
00
C
y
=
M
01
/
M
00
Cx = M_{10} / M_{00} \\ Cy = M_{01} / M_{00}
Cx=M10?/M00?Cy=M01?/M00?
2.2.4 轮廓的近似
轮廓的近似是用顶点数量较少的多边形对轮廓进行近似,可以使用函数 cv2. approxPolyDP() 实现。近似多边形的边数取决于设定的最大近似距离。
函数说明:
cv.approxPolyDP(curve, epsilon, closed[, approxCurve]) → approxCurve
- curve:以顶点构成的二维向量组表示的曲线(如轮廓列表 contours 中的一个轮廓)
- approxCurve:近似多边形顶点坐标 (x,y) 的二维向量组
- epsilon:近似精度,浮点数,原始曲线与近似多边形之间的最大距离
- closed:曲线闭合标志,True 表示近似曲线是闭合的
2.2.5 轮廓的凸包(凸壳)
物体的凸包(凸壳)是指包含该物体的最小凸面体。在二维图像中凸壳可以想象为一条刚好包着所有点的橡皮圈。在凸壳与物体边缘之间的部分称为凸陷(Convexity defect)。
OpenCV 中的函数 cv.isContourConvex() 测试轮廓是否为凸面体,函数 cv.convexHull() 获取轮廓的凸壳 。
函数说明:
cv.convexHull(points[, hull[, clockwise[, returnPoints]]]) → hull
cv.isContourConvex( contour) → retval
参数说明:
- points:二维点向量集
- contour:二维点向量集(如轮廓列表 contours 中的一个轮廓)
- hull:输出凸包,凸包顶点的索引向量,或凸包顶点坐标 (x,y) 的二维向量组
- clockwise:方向标志,默认值 False 表示逆时针方向输出凸包,True 为是顺时针
- returnPoints:操作标志,默认值 True 表示返回凸包点集, False 返回凸包点的索引
注意事项: 函数 cv.isContourConvex() 测试轮廓是否为凸面,输入的轮廓必须没有自交叉线。 函数 cv.convexHull() 与函数 cv.drawContours() 配合,可以用来检测物体是否存在缺陷。
例程 12.4:轮廓的面积、周长、质心和近似多边形
img = cv2.imread("../images/seagull01.png", flags=1)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
plt.figure(figsize=(9, 6))
plt.subplot(231), plt.axis('off'), plt.title("Origin")
plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
lowerBlue, upperBlue = np.array([100, 43, 46]), np.array([124, 255, 255])
segment = cv2.inRange(hsv, lowerBlue, upperBlue)
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))
binary = cv2.dilate(cv2.bitwise_not(segment), kernel=kernel, iterations=3)
plt.subplot(232), plt.axis('off'), plt.title("Tree contour")
plt.imshow(binary, 'gray')
contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
print("len(contours) = ", len(contours))
for i in range(len(contours)):
if hierarchy[0][i][3]==-1:
rect = cv2.minAreaRect(contours[i])
x, y = int(rect[0][0]), int(rect[0][1])
text = "{}:({},{})".format(i, x, y)
img = cv2.drawContours(img, contours, i, (255, 255, 255), -1)
img = cv2.putText(img, text, (x, y), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255))
plt.subplot(233), plt.axis('off'), plt.title("Contours")
plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
cnt = contours[0]
moments = cv2.moments(cnt)
huM = cv2.HuMoments(moments)
area = cv2.contourArea(cnt)
print("area by moments['m00']: ", moments['m00'])
print("area of contour: ", area)
if moments['m00'] > 0:
cx = round(moments['m10'] / moments['m00'])
cy = round(moments['m01'] / moments['m00'])
print("centroid of contour: ({}, {})".format(cx, cy))
cv2.circle(img, (cx, cy), 5, (0, 0, 255), -1)
plt.subplot(234), plt.axis('off'), plt.title("Contour centroid")
plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
else:
print("moments['m00'] = 0")
perimeter = cv2.arcLength(cnt, True)
print("centroid of perimeter: {:.1f}".format(perimeter))
epsilon = 0.01 * cv2.arcLength(contours[1], True)
approx = cv2.approxPolyDP(contours[1], epsilon, True)
approx.shape: (15, 1, 2)
cv2.polylines(img, [approx], True, (0, 0, 255), 2)
plt.subplot(235), plt.axis('off'), plt.title("Approximate polygon")
plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
isConvex = cv2.isContourConvex(contours[2])
print("contours[2] ContourConvex?", isConvex)
hull = cv2.convexHull(contours[2], returnPoints=True)
print("hull.shape: ", hull.shape)
cv2.polylines(img, [hull], True, (0, 0, 255), 2)
plt.subplot(236), plt.axis('off'), plt.title("Contour convex")
plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
plt.tight_layout()
plt.show()
运行结果:
len(contours) = 6
area by moments['m00']: 15523.0
area of contour: 15523.0
centroid of contour: (394, 380)
centroid of perimeter: 783.5
approx.shape: (15, 1, 2)
contours[2] ContourConvex? False
hull.shape: (24, 1, 2)
(本节完)
版权声明:
youcans@xupt 原创作品,转载必须标注原文链接:(https://blog.csdn.net/youcans/article/details/125023990)
Copyright 2022 youcans, XUPT Crated:2022-5-31
欢迎关注 『youcans 的 OpenCV 例程 200 篇』 系列,持续更新中 欢迎关注 『youcans 的 OpenCV学习课』 系列,持续更新中
【youcans 的 OpenCV 例程200篇】194.寻找图像轮廓(cv.findContours) 【youcans 的 OpenCV 例程200篇】195.绘制图像轮廓(cv.drawContours) 【youcans 的 OpenCV 例程200篇】196.图像的矩和不变矩(cv.moments) 【youcans 的 OpenCV 例程200篇】197.轮廓的基本特征 【youcans 的 OpenCV 例程200篇】198.基于不变矩的形状相似性检测 【youcans 的 OpenCV 例程200篇】199.轮廓的外接边界框 【youcans 的 OpenCV 例程200篇】200.轮廓的基本属性 更多内容,请见: 【OpenCV 例程200篇 总目录-202206更新】
|