youcans 的 OpenCV 例程200篇197.轮廓的基本特征

Posted 小白YouCans

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了youcans 的 OpenCV 例程200篇197.轮廓的基本特征相关的知识,希望对你有一定的参考价值。

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/M00Cy=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:轮廓的面积、周长、质心和近似多边形

    # 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 色彩空间图像分割
    hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)  # 将图片转换到 HSV 色彩空间
    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))  # (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')

    # 寻找二值化图中的轮廓
    # binary, contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)  # OpenCV3
    contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)  # OpenCV4~
    print("len(contours) = ", len(contours))  # 所有轮廓的列表

    # #  绘制全部轮廓,contourIdx=-1 绘制全部轮廓
    for i in range(len(contours)):  # 绘制第 i 个轮廓
        if hierarchy[0][i][3]==-1:  # 最外层轮廓
            rect = cv2.minAreaRect(contours[i])  # 最小外接矩形
            x, y = int(rect[0][0]), int(rect[0][1])  # 最小外接矩形的中心(x,y)
            text = ":(,)".format(i, x, y)
            img = cv2.drawContours(img, contours, i, (255, 255, 255), -1)  # 绘制第 i 个轮廓, 内部填充
            img = cv2.putText(img, text, (x, y), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255))
            # print("i=", i, ",contours[i]:", contours[i].shape, ",hierarchy[0][i] =", hierarchy[0][i], "text=", text)
    plt.subplot(233), plt.axis('off'), plt.title("Contours")
    plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))

    # 轮廓的特征矩
    cnt = contours[0]  # 第 0 个轮廓
    moments = cv2.moments(cnt)  # 返回字典,几何矩 mpq, 中心矩 mupq 和归一化矩 nupq
    huM = cv2.HuMoments(moments)  # 计算 Hu 不变矩

    # 轮廓面积
    area = cv2.contourArea(cnt)
    print("area by moments['m00']: ", moments['m00'])
    print("area of contour: ", area)

    # 轮廓的质心 (Cx, Cy)
    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)  # 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])  # True 凸面体, False 非凸
    print("contours[2] ContourConvex?", isConvex)
    # 获取轮廓的凸壳
    hull = cv2.convexHull(contours[2], returnPoints=True)  # 返回轮廓凸壳顶点坐标
    print("hull.shape: ", hull.shape)  # 凸壳顶点坐标 (x,y), (24, 1, 2)
    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.轮廓的基本特征
OpenCV 例程200篇 总目录-202205更新

以上是关于youcans 的 OpenCV 例程200篇197.轮廓的基本特征的主要内容,如果未能解决你的问题,请参考以下文章

youcans 的 OpenCV 例程200篇183.基于轮廓标记的分水岭算法

youcans 的 OpenCV 例程200篇182.基于形态学梯度的分水岭算法

youcans 的 OpenCV 例程200篇结束语

youcans的OpenCV例程200篇总目录

youcans 的 OpenCV 例程200篇179.图像分割之 GrabCut 图割法(掩模图像)

youcans 的 OpenCV 例程200篇201. 图像的颜色空间转换