Opencv---RotatedRect

在Robomaster比赛中,RotatedRect类极为常用,灯条、装甲板以至于整车都可以用RotatedRect类来表示。

一、基本概念与用途

RotatedRect 是OpenCV中用于表示旋转矩形的类,常用于需要描述矩形方向(角度)的场景,如:

  • 目标检测中的倾斜边界框(如灯条、装甲板、车牌、文本检测)。
  • 形状分析中的方向感知(如椭圆拟合后的方向)。
  • 几何变换中的旋转矩形表示。

与普通轴对齐矩形 Rect 的区别:

  • Rect 仅包含位置和尺寸(轴对齐)。
  • RotatedRect 包含中心点、尺寸、旋转角度,可表示任意方向的矩形。
二、类定义与构造函数
1. 成员变量(C++)
cpp 复制代码
class RotatedRect {
public:
    Point2f center;   // 中心点坐标(x, y)
    Size2f size;      // 矩形尺寸(宽, 高)
    float angle;      // 旋转角度(单位:度,逆时针为正)
    // 构造函数、成员函数...
};
2. 构造方式
  • 标准构造 :通过中心点、尺寸、角度初始化。

    cpp 复制代码
    // C++
    RotatedRect rRect(Point2f(cx, cy), Size2f(w, h), angle);
    
    // Python
    rRect = cv2.RotatedRect((cx, cy), (w, h), angle)
  • 从轮廓/点集拟合 :通过 minAreaRect() 函数从点集计算最小面积旋转矩形。

    cpp 复制代码
    // C++
    vector<Point2f> points; // 轮廓点集
    RotatedRect rRect = minAreaRect(points);
    
    // Python
    rRect = cv2.minAreaRect(cnt)  # cnt为轮廓点集(numpy数组)
三、核心知识点讲解
1. 旋转角度(angle)的定义
  • 方向 :矩形的水平轴 (长边)与图像坐标系x轴的夹角,逆时针为正
  • 范围约定 :OpenCV中 angle 通常位于 -90° < angle ≤ 0° 。当矩形竖放时(高 > 宽),会自动交换宽高,并将角度调整为 -90° < angle ≤ 0° 。例如:
    • 若原始宽=20,高=40,角度=30°,则实际存储为宽=40,高=20,角度=-60°(保证宽≥高,角度在约定范围)。
2. 顶点坐标计算(points()函数)

通过 RotatedRectpoints() 方法(C++)或 cv2.boxPoints()(Python)获取矩形的4个顶点,顺序为:

  1. 左上角顶点(中心点左侧,沿旋转方向第一个点)。
  2. 右上角顶点(中心点右侧,顺时针第二个点)。
  3. 右下角顶点
  4. 左下角顶点

示例代码

cpp 复制代码
// C++
vector<Point2f> vertices;
rRect.points(vertices); // vertices包含4个顶点,顺序如上述

// Python
vertices = cv2.boxPoints(rRect)  # 返回numpy数组,形状为(4,2)
3. 与轴对齐矩形(Rect)的转换
  • 获取包围旋转矩形的最小轴对齐矩形

    cpp 复制代码
    Rect boundRect = rRect.boundingRect2f(); // C++,返回浮点型Rect
    python 复制代码
    x, y, w, h = cv2.boundingRect(vertices.astype(int))  # Python,需先转换为整数顶点
  • 旋转矩形转普通矩形:仅取顶点坐标的极值,不保留角度信息。

4. 几何运算
  • 面积与周长

    cpp 复制代码
    float area = rRect.size.width * rRect.size.height; // 面积
    float perimeter = 2 * (rRect.size.width + rRect.size.height); // 周长(非旋转周长)
  • 旋转矩阵计算 :以中心点为原点,计算旋转后的坐标变换矩阵:

    cpp 复制代码
    Mat rotationMat = getRotationMatrix2D(rRect.center, rRect.angle, 1.0); // 旋转矩阵
5. 绘制与可视化

通过顶点坐标绘制旋转矩形:

cpp 复制代码
// C++
for (int i = 0; i < 4; i++) {
    line(img, vertices[i], vertices[(i+1)%4], Scalar(0, 255, 0), 2);
}

// Python
for i in range(4):
    cv2.line(img, tuple(vertices[i].astype(int)), tuple(vertices[(i+1)%4].astype(int)), (0, 255, 0), 2)
6. 碰撞检测(两旋转矩形相交判断)

OpenCV未直接提供相交检测函数,需手动实现:

  1. 将旋转矩形转换为多边形(4顶点)。

  2. 使用 分离轴定理(SAT)多边形相交算法 判断是否相交。

  3. 示例思路:

    python 复制代码
    def is_rotated_rect_intersect(r1, r2):
        box1 = cv2.boxPoints(r1).astype(int)
        box2 = cv2.boxPoints(r2).astype(int)
        # 转换为凸多边形,使用cv2.pointPolygonTest判断点是否在另一多边形内
        for p in box1:
            if cv2.pointPolygonTest(box2, tuple(p), False) >= 0:
                return True
        for p in box2:
            if cv2.pointPolygonTest(box1, tuple(p), False) >= 0:
                return True
        return False
四、注意事项与常见误区
  1. 角度与宽高的绑定关系

    • angle(-90°, 0] 时,size.width ≥ size.height(长边为水平轴)。
    • 若手动设置 angle > 0°size.width < size.height,OpenCV会自动调整宽高和角度,以保证约定范围。
  2. 顶点顺序的一致性

    • points() 返回的顶点顺序固定,可通过顺时针或逆时针顺序绘制闭合矩形。
  3. 浮点精度问题

    • 顶点坐标默认为浮点型,绘制时需转换为整数(astype(int)),避免亚像素误差。
  4. 与椭圆(Ellipse)的区别

    • RotatedRect 是矩形,Ellipse 是椭圆,拟合时根据形状选择工具(如 fitEllipse() 返回椭圆,minAreaRect() 返回矩形)。
五、应用场景示例
1. 目标检测中的倾斜边界框
python 复制代码
# 假设检测到轮廓cnt,提取旋转矩形
cnt = ... # 轮廓点集
rRect = cv2.minAreaRect(cnt)
vertices = cv2.boxPoints(rRect).astype(int)
cv2.polylines(img, [vertices], isClosed=True, color=(0, 255, 0), thickness=2)
2. 形状方向分析
cpp 复制代码
// 计算矩形的主方向(角度)
float angle = rRect.angle;
if (angle < -45) angle += 90; // 转换为0°~90°范围的方向角
3. 图像旋转后的边界框调整
python 复制代码
# 对图像旋转θ角后,重新计算旋转矩形的位置
def rotate_image_with_box(img, rRect, theta):
    rows, cols = img.shape[:2]
    M = cv2.getRotationMatrix2D(rRect.center, theta, 1.0)
    rotated_img = cv2.warpAffine(img, M, (cols, rows))
    # 调整旋转矩形的角度
    new_rRect = cv2.RotatedRect(rRect.center, rRect.size, rRect.angle + theta)
    return rotated_img, new_rRect
六、跨语言差异(C++ vs Python)
特性 C++ Python
构造函数参数 Point2f, Size2f, float 元组 (cx, cy), (w, h), float
顶点获取 points(vector<Point2f>&) cv2.boxPoints(rRect) 返回numpy数组
序列化 需手动存储成员变量 可转为元组或JSON存储
七、数学原理补充(顶点坐标推导)

设中心点为 (c_x, c_y),尺寸为 (w, h),角度为 θ,则4个顶点坐标可通过旋转矩阵计算:

  • 原始矩形(未旋转)的顶点相对于中心点的坐标:
    (±w/2, ±h/2)(左上:(-w/2, -h/2),右上:(w/2, -h/2),右下:(w/2, h/2),左下:(-w/2, h/2))。

  • 旋转θ角后的坐标:

    x ′ y ′ \] = \[ cos ⁡ θ − sin ⁡ θ sin ⁡ θ cos ⁡ θ \] \[ x y \] + \[ c x c y \] \\begin{bmatrix} x' \\\\ y' \\end{bmatrix} = \\begin{bmatrix} \\cosθ \& -\\sinθ \\\\ \\sinθ \& \\cosθ \\end{bmatrix} \\begin{bmatrix} x \\\\ y \\end{bmatrix} + \\begin{bmatrix} c_x \\\\ c_y \\end{bmatrix} \[x′y′\]=\[cosθsinθ−sinθcosθ\]\[xy\]+\[cxcy

  • 代入4个顶点的原始坐标,得到旋转后的绝对坐标。


我们太看重了白昼,又太忽视着黑夜。生命,至少有一半是在黑夜中呀。 ---史铁生

相关推荐
美林数据Tempodata35 分钟前
大模型驱动数据分析革新:美林数据智能问数解决方案破局传统 BI 痛点
数据库·人工智能·数据分析·大模型·智能问数
硅谷秋水38 分钟前
NORA:一个用于具身任务的小型开源通才视觉-语言-动作模型
人工智能·深度学习·机器学习·计算机视觉·语言模型·机器人
whoarethenext40 分钟前
使用 C/C++的OpenCV 裁剪 MP4 视频
c语言·c++·opencv
正儿八经的数字经44 分钟前
人工智能100问☞第46问:AI是如何“学习”的?
人工智能·学习
飞哥数智坊1 小时前
别卷提示词了!像带新人一样“带”AI,产出效率翻倍
人工智能
扫地的小何尚1 小时前
全新NVIDIA Llama Nemotron Nano视觉语言模型在OCR基准测试中准确率夺冠
c++·人工智能·语言模型·机器人·ocr·llama·gpu
m0_575470882 小时前
n8n实战:自动化生成AI日报并发布
人工智能·ai·自动化·ai自动写作
时空无限2 小时前
使用 ollama 在 mac 本地部署一个 qwen3:8b 模型
人工智能·语言模型
平行云2 小时前
LarkXR 赋能AI x XR数字供应链:引领智能设计、数字孪生与零售新未来
人工智能·webrtc·xr·云渲染·虚幻引擎·云展厅