• (十三) minAreaRect函数



    欢迎访问个人网络日志🌹🌹知行空间🌹🌹


    1.背景

    在做旋转物体检测时,通常期望得到对象的带角度最小面积包围矩形,如下图对卫星图像航空母舰的检测:

    在这里插入图片描述

    若已经获取了对象的轮廓,可以通过OpenCV中的minAreaRect方法获取对象的最小面积包围框。

    2.minAreaRect 函数

    RotatedRect cv::minAreaRect(InputArray 	points)	
    
    • 1

    入参

    • points 是点的集合,如轮廓

    返回值

    center(x,y), (width, height)分别是旋转矩形框中心的坐标和矩形的宽和高。值得注意的是最后一个元素angle of rotation旋转角的定义。旧版本和新版本的定义有些许的差异,具体是以4.5.1为分界,小于4.5.1使用了旧的定义方法,4.5.1及之后都采用了新的旋转角定义方法。具体可见OpenCV GitHub Issue。新旧版本旋转角度的定义如下【图片来自于 mmRotate】:

    在这里插入图片描述

    对于新版的定义,以旋转矩形框x最小,y最小的点为旋转点,以x轴正方向开始顺时针旋转碰到旋转矩形框第一条边时所转过的角度,旋转重合的第一条边算做width,另一条算做height,其取值范围为 ( 0 , π / 2 ] (0, \pi/2] (0,π/2],当x轴与一条边重合时取 π / 2 \pi/2 π/2。对于旧版的定义,以旋转矩形框y最小,x最小的点为旋转点, 逆时针方向旋转碰到的第一条边与x轴所成的角,其取值范围为 [ − π / 2 , 0 ) [-\pi/2,0) [π/2,0)

    3.以新版为例

    img = np.zeros((300, 500), dtype=np.uint8)
    contour = np.array([[20, 100], [100, 20], [320, 220], [380, 290]], dtype=np.int32)
    cv2.drawContours(img, [contour], -1, 255, cv2.FILLED )
    rotRect = cv2.minAreaRect(contour) # 返回值 (center(x,y), (width, height), angle of rotation )
    print(rotRect)
    rect = cv2.boxPoints(rotRect).astype(np.int32)
    img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
    cv2.drawContours(img, [rect], -1, (0,0, 255), 4)
    cv2.imwrite("img.png", img)
    # >>>
    # ((225.22630310058594, 147.20277404785156), (407.0626525878906, 108.09146881103516), 27.8240966796875)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在这里插入图片描述

    cv2.minAreaRect函数的返回值是旋转矩形框中心点的坐标和框的宽高,想要在图像画出旋转矩形框还需要将其转成4个顶点的形式,使用boxPoints即可求出四个顶点的坐标。此外还可以手动的来求,也比较简单,假设以旋转点为原点,矩形框width的边为新的x轴建立新的坐标系,则和原图像坐标系之间是只有旋转变换,求出其旋转矩阵即可完成点的变换,可参考,代码如下,可见结果很接近(计算精度存在误差):

    
    def rotate_oc_points(bbox):
        xc, yc, w, h, ag = bbox[:5]
        ag = ag/180*np.pi
        wx, wy = w / 2 * np.cos(ag), w / 2 * np.sin(ag)
        hx, hy = -h / 2 * np.sin(ag), h / 2 * np.cos(ag)
        p1 = (xc - wx - hx, yc - wy - hy)
        p2 = (xc + wx - hx, yc + wy - hy)
        p3 = (xc + wx + hx, yc + wy + hy)
        p4 = (xc - wx + hx, yc - wy + hy)
        return np.array([p1, p2, p3, p4], dtype=np.int32)
    
    img = np.zeros((300, 500), dtype=np.uint8)
    contour = np.array([[20, 100], [100, 20], [320, 220], [380, 290]], dtype=np.int32)
    cv2.drawContours(img, [contour], -1, 255, cv2.FILLED )
    rotRect = cv2.minAreaRect(contour) # 返回值
    rect = cv2.boxPoints(rotRect).astype(np.int32)
    print(f"by boxPoints:\n {rect}")
    rect = rotate_oc_points([*rotRect[0], *rotRect[1], rotRect[2]])
    print(f"by rotate_oc_points:\n {rect}")
    img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
    cv2.drawContours(img, [rect], -1, (0,0, 255), 4)
    cv2.imwrite("img.png", img)
    
    # >>>
    # by boxPoints:
    #  [[ 19  99]
    #  [ 70   4]
    #  [430 194]
    #  [380 290]]
    # by rotate_oc_points:
    #  [[ 70   4]
    #  [430 194]
    #  [379 289]
    #  [ 19  99]]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    欢迎访问个人网络日志🌹🌹知行空间🌹🌹


    参考资料

  • 相关阅读:
    Facebook账号运营技巧
    zookeper&kafka学习
    Problem: 205. 同构字符串;力扣;python
    Complex analysis
    算法-贪心算法-简单-买卖股票的最佳时机
    MySQL INTERVAL 关键字指南
    PixiJS源码分析系列:第二章 渲染在哪里开始?
    设计模式的思考(四)
    Java 类的结构其一:构造器(或构造方法)的使用
    使用flutter的Scaffold脚手架开发一个最简单的带tabbar的app模板
  • 原文地址:https://blog.csdn.net/lx_ros/article/details/126275103