【youcans 的 OpenCV 例程200篇】199.轮廓的外接边界框

OpenCV 例程200篇 总目录-202206更新


【youcans 的 OpenCV 例程200篇】199.轮廓的外接边界框


2. 轮廓的特征描述

在对实际图像进行轮廓查找时,得到的轮廓数量很多。获取轮廓后,通常基于轮廓的特征进行筛选、识别和处理。例如,基于轮廓的周长和面积对轮廓进行筛选,然后绘制筛选的目标轮廓或其最小外接矩形。

常用的轮廓特征,包括图像距、轮廓周长、轮廓近似、凸包、边界矩形、拟合图形等特征。


2.3 轮廓的外接边界框

通过轮廓的外接矩形、外接圆或椭圆,计算几何形状的横纵比、面积、周长,可以实现特定几何形状轮廓的查找与过滤, 为后续的处理与分析筛选目标。

2.3.1 轮廓的垂直矩形边界框

垂直矩形边界框是指平行于图像侧边的矩形框。用于不考虑旋转,垂直边界框不是轮廓的最小矩形边界框。

函数 cv2. boundingRect() 可以获得轮廓的垂直矩形边界框。

函数说明:

cv.boundingRect(array) → retval

参数说明:

  • array:灰度图像,或顶点构成的二维向量组(如轮廓列表 contours 中的一个轮廓)
  • retval:返回值结构 (x, y, w, h),矩形左上顶点坐标 x, y,矩形的宽度 w,高度 h

2.3.2 轮廓的最小矩形边界框

轮廓的最小矩形边界框是面积最小的轮廓外接矩形框,最小矩形边界框通常与图像侧边有旋转角。

函数 cv2. minAreaRect () 可以获得轮廓的最小矩形边界框,函数 cv2.boxPoints() 计算旋转矩形的顶点。

函数说明:

cv.minAreaRect(points) → retval
cv.boxPoints(box[, points]) → points

参数说明:

  • points:二维点向量集 (x,y)
  • retval = [(x,y), (w,h), ang]: Box2D 结构,矩形中心点坐标 (x,y),矩形宽高 (w,h),旋转角度 ang
  • box: Box2D 结构,旋转矩形(如函数 cv.minAreaRect() 的输出)

注意事项:

水平轴逆时针旋转,直到矩形的第一条边,该边与水平轴的夹角为旋转角度 ang,这条边的边长为 width。

当数据接近包含的元素边界时,返回的 RotatedRect 可以包含负索引。


2.3.3 轮廓的最小外接圆

轮廓的最小外接圆是面积最小的轮廓外接圆。

函数 cv2. minAreaRect() 可以获得轮廓的最小外接圆。

函数说明:

cv.minEnclosingCircle(points) → center, radius

参数说明:

  • points:二维点向量集
  • center:外接圆的圆心坐标 (Cx, Cy),浮点数
  • radius:外接圆的半径,浮点数

2.3.4 轮廓的最小外接三角形

轮廓的最小外接三角形是面积最小的轮廓外接三角形。

函数 cv2. minEnclosingTriangle () 可以获得轮廓的最小外接圆。

函数说明:

cv.minEnclosingTriangle(points[, triangle]) → retval, triangle

参数说明:

  • points:二维点向量集,数据类型为 CV_32S 或 CV_32F
  • retval:三角形的面积,浮点数
  • triangle:三角形的顶点坐标,形状 (3,1,2),数据类型为 CV_32F

2.3.5 轮廓的最小拟合椭圆

函数 cv2. fitEllipse() 根据一组二维点向量拟合椭圆。

函数说明:

cv.fitEllipse(points) → retval

参数说明:

  • points:二维点向量集
  • retval = [(x,y), (a,b), ang],椭圆中心点坐标 (x,y),椭圆短轴、长轴长度 (a,b),旋转角度 ang

旋转角度 ang 表示短轴 a 与水平轴的夹角,顺时针为正。


2.3.6 轮廓的拟合直线

函数 cv2. fitLine() 用一条直线拟合到一组二维点向量。

函数说明:

cv.fitLine(points, distType, param, reps, aeps[, line] ) → line

参数说明:

  • points:二维或三维点向量集
  • line:拟合直线,(vx, vy, x0, y0),(vx,vy) 是与直线共线的归一化向量,(x0,y0) 是直线上的点
  • distType:距离类型, cv.DIST_L1、cv.DIST_L2、cv.DIST_C、cv.DIST_L12
  • param:某些类型距离的参数(C),0 表示选择最佳值
  • reps:距离精度,原点与直线的间距
  • aeps:角度精度,推荐值 0.01

2.3.7 形状相似度检测

函数 cv2.matchShapes() 基于 Hu 不变矩检测两个形状之间的相似度,返回值越小表明形状越相似。

函数说明:

cv.matchShapes(contour1, contour2, method, parameter) → retval

参数说明:

  • contour1:第 1 个轮廓,或灰度图像
  • contour2:第 2 个轮廓,或灰度图像
  • method:比较方法,可选项:cv.CONTOURS_MATCH_I1、cv.CONTOURS_MATCH_I2、cv.CONTOURS_MATCH_I3

例程 12.5:轮廓的外接边界框

    # 12.5 轮廓的外接边界框
    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)  # 图像膨胀

    # 寻找二值化图中的轮廓
    # 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~

    # #  绘制全部轮廓,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))

    cnt = contours[1]
    moments = cv2.moments(cnt)  # 返回字典,几何矩 mpq, 中心矩 mupq 和归一化矩 nupq
    cx = round(moments['m10'] / moments['m00'])
    cy = round(moments['m01'] / moments['m00'])
    cv2.circle(img, (cx, cy), 5, (0, 0, 255), -1)  # 在轮廓的质心上绘制圆点
    print("Centroid of contour: ({}, {})".format(cx, cy))

    # 轮廓的垂直矩形边界框
    # boundingBoxes = [cv2.boundingRect(cnt) for cnt in contours]  # 所有轮廓的外接垂直矩形
    x, y, w1, h1 = cv2.boundingRect(cnt)  # 矩形左上顶点的坐标 x, y, 矩形宽度 w, 高度 h
    print("Vertical rectangle: (x,y)={}, (w,h)={}".format((x, y), (w1, h1)))
    img1 = img.copy()
    cv2.rectangle(img1, (x, y), (x+w1, y+h1), (0, 0, 255), 2)  # 绘制垂直矩形边界框

    # 轮廓的最小矩形边界框
    rect = cv2.minAreaRect(cnt)  # 中心点 (x,y), 矩形宽度高度 (w,h), 旋转角度 ang
    (x, y), (w2, h2), ang = np.int32(rect[0]), np.int32(rect[1]), round(rect[2], 1)
    box = np.int32(cv2.boxPoints(rect))  # 计算旋转矩形的顶点, (4, 2)
    cv2.drawContours(img1, [box], 0, (0, 0, 255), 2)  # # 将旋转矩形视为一个轮廓进行绘制
    print("Minimum area rectangle: (Cx,Cy)={}, (w,h)={}, ang={})".format((x, y), (w2, h2), ang))
    plt.subplot(232), plt.axis('off'), plt.title("Rectangle bounding")
    plt.imshow(cv2.cvtColor(img1, cv2.COLOR_BGR2RGB))

    # 轮廓的最小外接圆
    (x, y), r = cv2.minEnclosingCircle(cnt)  # 圆心 (x,y), 半径 r
    Cx, Cy, radius = int(x), int(y), int(r)
    img2 = img.copy()
    cv2.circle(img2, (Cx, Cy), radius, (0, 255, 0), 2)
    print("Minimum circle: (Cx,Cy)=({},{}), r={}".format(Cx, Cy, radius))
    plt.subplot(233), plt.axis('off'), plt.title("Circumcircle ")
    plt.imshow(cv2.cvtColor(img2, cv2.COLOR_BGR2RGB))

    # 轮廓的最小外接三角形
    area, triangle = cv2.minEnclosingTriangle(cnt)  # area 三角形面积, triangle 三角形顶点 (3,1,2)
    intTri = np.int32(triangle)
    img3 = img.copy()
    cv2.polylines(img3, [intTri], True, (255, 0, 0), 2)
    plt.subplot(234), plt.axis('off'), plt.title("Circumscribed triangle")
    plt.imshow(cv2.cvtColor(img3, cv2.COLOR_BGR2RGB))

    # 轮廓的拟合椭圆
    ellipse = cv2.fitEllipse(cnt)  # 椭圆中心点 (x,y), 宽度高度 (w,h), 旋转角度 ang
    (x, y), (w3, h3), ang = np.int32(ellipse[0]), np.int32(ellipse[1]), round(ellipse[2], 1)
    print("Fitted ellipse: (Cx,Cy)={}, (w,h)={}, ang={})".format((x, y), (w3, h3), ang))
    img4 = img.copy()
    cv2.ellipse(img4, ellipse, (0, 255, 255), 2)
    plt.subplot(235), plt.axis('off'), plt.title("Fitted ellipse")
    plt.imshow(cv2.cvtColor(img4, cv2.COLOR_BGR2RGB))

    # # 拟合直线
    rows, cols = img.shape[:2]
    [vx, vy, x, y] = cv2.fitLine(cnt, cv2.DIST_L1, 0, 0.01, 0.01)
    lefty = int((-x * vy/vx) + y)
    righty = int(((cols - x) * vy/vx) + y)
    img5 = img.copy()
    cv2.line(img5, (0,lefty), (cols-1,righty), (255, 0, 0), 2)
    plt.subplot(236), plt.axis('off'), plt.title("Fitted line")
    plt.imshow(cv2.cvtColor(img5, cv2.COLOR_BGR2RGB))

    print("area of contour[1]: ", cv2.contourArea(cnt))  # 轮廓的面积
    print("area of VerticalRectangle: ", w1*h1)  # 轮廓垂直外接矩形的面积
    print("area of MinAreaRectangle: ", w2*h2)  # 轮廓最小外接矩形的面积
    print("area of MinAreaTriangle: ", int(area))  # 轮廓最小外接三角形的面积

    plt.tight_layout()
    plt.show()

运行结果:

Centroid of contour: (227, 263)
Vertical rectangle: (x,y)=(168, 173), (w,h)=(132, 156)
Minimum area rectangle: (Cx,Cy)=(215, 267), (w,h)=(178, 106), ang=60.6)
Minimum circle: (Cx,Cy)=(246,250), r=89
Fitted ellipse: (Cx,Cy)=(225, 265), (w,h)=(101, 173), ang=155.4)
area of contour[1]:  9302.5
area of VerticalRectangle:  20592
area of MinAreaRectangle:  18868
area of MinAreaTriangle:  13913

在这里插入图片描述


(本节完)


版权声明:
youcans@xupt 原创作品,转载必须标注原文链接:(https://blog.csdn.net/youcans/article/details/125024042)
Copyright 2022 youcans, XUPT
Crated:2022-5-28
欢迎关注 『youcans 的 OpenCV 例程 200 篇』 系列,持续更新中
欢迎关注 『youcans 的 OpenCV学习课』 系列,持续更新中
更多内容,请见:
【OpenCV 例程200篇 总目录-202206更新】

194.寻找图像轮廓(cv.findContours)
195.绘制图像轮廓(cv.drawContours)
196.图像的矩和不变矩(cv.moments)
197.轮廓的基本特征
198.基于不变矩的形状相似性检测
199.轮廓的外接边界框
200.轮廓的基本属性

猜你喜欢

转载自blog.csdn.net/youcans/article/details/125024042