minAreaRect返回的数据包括了矩形的中心点,宽、高,和旋转角度。
其中旋转角度的范围是[-90,0),在第一、第二象限有不同的表现形式,更重要的是,宽高也会跟着旋转而发生变化。
下面是实验的模拟:
首先创建一个矩形图,如下图所示,初始水平,宽,高分别为200和70。minArea对这个初始矩形轮廓的返回角度为-90
接下来,让矩形逆时针旋转,每次旋转15度,(键盘任意键按下为一次旋转),下面的动图展示了整个旋转过程(360度)中minAreaRect返回的角度与宽高值。
可以发现,在第一象限时,水平方向在opencv中表示为-90,但实际上往逆时针稍微旋转一点,就是0,逆时针方向旋转角度减少,直达-90变成垂直。第二象限时,角度垂直时opencv中表示为-90,也与之前第一象限的角度连续,但实际上往逆时针方向转一点,也就变成了0度,然后逆时针转到水平时为-90度(也与第一象限的初始位置角度连续)。
特别注意,在第二象限时,opencv返回的宽高是实际矩形的高、宽。第一象限时宽高没有交换。
ps:针对这一点特性,若需要利用minAreaRect返回的角度值对图片进行矫正,则可以通过该函数返回的矩形宽、高之比进行判定,若小于1(宽小于高),则表明图形处于第二象限,利用getRotationMatrix2D(center, angle,1)函数进行变换时,angle就需要加上90.(因为getRotationMatrix2D中的angle参数为正时表示逆时针旋转)
即opencv中的minAreaRect在第一象限的返回结果如下:
opencv中的minAreaRect在第二象限的返回结果如下:
实验程序如下:
import cv2
import numpy as np
import matplotlib.pyplot as plt
import imutils
if __name__ == '__main__':
image = np.zeros((400, 400), dtype='uint8')
image[180:251, 100:301] = 255
# loop over the rotation angles
for angle in np.arange(0, 360, 15): # 逆时针旋转
rotated = imutils.rotate(image, angle)
try:
_, contours, hierarchy = cv2.findContours(rotated, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
except ValueError:
contours, hierarchy = cv2.findContours(rotated, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
rotatedRect = cv2.minAreaRect(contours[0])
angle = rotatedRect[-1]
w, h = rotatedRect[1]
print("angle:", angle)
print("size:", rotatedRect[1])
cv2.putText(rotated, 'angle:' + str(int(angle)), (100, 25), cv2.FONT_HERSHEY_SIMPLEX, 1, 255)
cv2.putText(rotated, '(h,w):({0},{1})'.format(int(h), int(w)), (80, 60), cv2.FONT_HERSHEY_SIMPLEX, 1, 255)
cv2.imshow("Rotated (Problematic)", rotated)
cv2.waitKey(0)
cv2.destroyAllWindows()