cv2.minAreaRect角度问题与cv2.boxPoints点顺序问题

1. cv2.minAreaRect

  cv2.minAreaRect是用于计算一组点的最小外接矩形的函数。

  输入:points为轮廓或多边形点集,形状为(N,2),类型为numpy.ndarray 或 list,数据类型为整数或浮点数。

  输出:包含三个元素的元组((cx, cy), (width, height), angle),其中cx,cy,width, height,angle均为float类型,分别代表中最小外接矩形的心点坐标,宽,高,旋转角度

 2.cv2.minAreaRect返回值的角度范围与角度的定义及宽高的确定

  从上面的输出中可以看到最后一个返回值为angle,对于角度范围于定义如下:

  OpenCV 4.5及之后版本:角度范围为(0, 90],表示x轴顺时针旋转到第一次接触到矩形边界时的角度,定义该边为width

  OpenCV 4.5之前版本:角度范围为[-90, 0),表示x轴逆时针旋转到第一次接触到矩形边界时的角度,定义该边为width

  这里以高版本的OpenCV (OpenCV 4.5及之后版本)为例,看示意图:

  当与水平有一定的倾斜角度a时,x轴顺时针旋转a先重合的边定义为返回值中的width,另外一边定义为height。

 

  x轴顺时针旋转a后就重合的一边为返回值的width。

  但如果是正矩形,首先我们知道了角度范围为(0, 90],不可能为0,必定要旋转,所以对于没有倾斜角度的矩形,其旋转角度为90度。根据旋转规则,示意图如下:

  x轴顺时针旋转a后就重合的一边为返回值的width。

  对于正矩形,从上图可以看出与我们平时视觉认为的宽高有所不同。

3. cv2.boxPoints返回值点坐标顺序

  这里以opencv4.5.3为例,其他版本没有验证过。

  使用rect=cv2.minAreaRect(points)得到最小外接矩形的中心点坐标,宽,高,旋转角度外,常常需要获取这个最小外接矩形的四个顶点的坐标,需要使用box = cv2.boxPoints(rect)获取,然后使用box = np.int0(box)或box =np.int_(box)进一步将坐标转换成整数。这里先说结论,如果矩形没有倾斜的角度,那么得到的box的四个点坐标顺序为左上,右上,右下,左下;如果有倾斜角(0,90),则第一个至第四个点顺序为左(xmin),上(ymin),右(xmax),下(ymax);具体看下面程序与示意图:

  这里角度仍然以顺时针角度(0,90]范围作为讨论:

import cv2
import numpy as np
image = np.zeros((500, 500, 3), dtype=np.uint8) # 定义矩形的中心点、宽度、高度和旋转角度
center = (250, 250) # 中心点坐标
width = 100
height = 50
angle = 45 # 旋转角度,单位为度
rect = ((center[0], center[1]), (width, height), angle)
box = cv2.boxPoints(rect)  # 计算旋转矩形的四个顶点
box = np.int0(box) # 将顶点坐标转换为整数

for i, point in enumerate(box):
    print(f"点 {i + 1}: {point}") # 打印矩形的四个顶点坐标 print("矩形的四个顶点坐标:")
cv2.drawContours(image, [box], 0, (0, 255, 0), 2)
# 在每个顶点位置绘制文本数字
for i, point in enumerate(box):
cv2.putText(image, str(i + 1), tuple(point), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2)
cv2.imshow("Rotated Rectangle", image) cv2.waitKey(0) cv2.destroyAllWindows()

 

   将上述程序的angle=45改为90度,效果如下:

  与前面讨论的90度情况下一致,宽为竖边100,高为横边50。

4. 获取某个轮廓(多边形点集)的最小外接矩形

  程序使用的原始图

import cv2
import numpy as np

# 读取图片
image = cv2.imread('oval.png')  # 替换为你的图片路径
if image is None:
    print("图片加载失败,请检查路径!")
    exit()

# 将图片转换为灰度图
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
#生成二值图
### binary = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY_INV, 11, 2)
# 使用大津法进行阈值化生成二值图
_, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
cv2.imshow("binary", binary)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 查找轮廓
contours, _ = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 假设最大的轮廓是椭圆
if contours:
    # 找到面积最大的轮廓
    largest_contour = max(contours, key=cv2.contourArea)
    # 计算最小外接矩形
    rect = cv2.minAreaRect(largest_contour)
    box = cv2.boxPoints(rect)
    box = np.int0(box)
    # 打印最小外接矩形的信息
    print("最小外接矩形信息:")
    print(f"中心点: {rect[0]}")
    print(f"宽度: {rect[1][0]}")
    print(f"高度: {rect[1][1]}")
    print(f"旋转角度: {rect[2]}")
    # 在原图上绘制最小外接矩形
    cv2.drawContours(image, [box], 0, (0, 0, 255), 2)  # 使用红色绘制
# 显示结果
cv2.imshow("Image with Min Area Rectangle", image)
cv2.waitKey(0)
cv2.destroyAllWindows()

  运行结果如下:

                                  

 

小结:对cv2.minAreaRect与cv2.boxPoints进行了分析,本文测试均是采用opencv4.5.3版本在分析cv2.boxPoints返回值的角度问题时,只讨论(0,90]度的情况是为了保持与cv2.minAreaRect中返回的角度一致,尽管cv2.boxPoints(rect) 中rect里面的angle输入值是可以超过这个范围的,这里不再讨论其输出与规律;

 

 

 

  若有不足之处。欢迎评价与讨论!

posted @ 2025-05-18 15:59  wancy  阅读(1178)  评论(0)    收藏  举报