RotatedRect和minAreaRect源代码学习笔记

我们在使用opencv处理图像的轮廓时,通常会用到RotatedRect。RotatedRect不是横平竖直的矩形,每个RotatedRect由中心点(质心)、每条边的长度(由 Size2f 结构表示)和以度为单位的旋转角度指定。
本文将记录RotatedRect和minAreaRect相关的源码(20220323版本)的学习笔记,本文实验用opencv4.5.5+VS2019。

参考链接

以下图片来自于文章cv2.minAreaRect(),感谢原作者!

minAreaRect angle

1. RotatedRect类的成员函数

这里我们主要学习RotatedRect有三个点的构造函数和Points函数,我们先来看RotatedRect的构造函数。

该函数介绍中说明了可以用3个按逆时针或顺时针顺序给出的点来构造一个RotatedRect,以下是该构造函数的源代码:

从该函数的源代码第10行可知,构造RotatedRect时给出的三个3个点除了需要按顺时针或逆时针的方向给出外,这三个点构成的两个向量还需要是垂直的。

那么用三个点构造的RotatedRect中,该如何确认其width,height和angle呢?

由源代码第15行可知,width和height由第2,3两个点组成的向量来决定。源代码中计算width,height和angle的方法与OpenCV之RotatedRect基本用法和角度探究讲到的规则相符:

1. angle范围是[-45°,45°],

2. 确定width的方法:找到最下面的顶点,设定水平轴,左边(正)和右边(负)分别得到一个角度,以绝对值小的那个角度为angle,接触的边为width。比如下图,就是左边的角为angle,正值,其边为width。

接下来我们来看points的函数说明cv::RotatedRect Class Reference

points的源代码如下:

由代码以及说明可知,当我们使用如下代码来获取RotatedRect的四个点时,rect_points[0],rect_points[1],rect_points[2],rect_points[3]分别对应的是RotatedRect左下,左上,右上,右下四个点。

注意:这个说法目前只能确保在Opencv4.5.5中以及20220323对应的opencv源代码中是成立的,并不适用于所有版本。关于Points输出的四个点的顺序,以及minAreaRect的width/height/angle在不同版本中会有不同的规则,在github/opencv 可以看到多个相关的issues,例如Specify the return value (angle) of minAreaRect()

2. minAreaRect

minAreaRect的源代码在minAreaRect第360行,如下所示:

这里我们只关注第19~37的代码。第21行函数rotatingCalipers(该函数的源代码与minAreaRect在同一文件中)的关于输出描述如下:

在minAreaRect的源码中,我们知道width和angle均由out[1]的坐标计算得到。但是从rotatingCalipers的源码中我们没有看到明确的代码来说明向量out[1]坐标值的正负,因此没有明确的代码来证明angle的值的范围和以及其确认方式。

OpenCV之RotatedRect基本用法和角度探究cv2.minAreaRect()这两篇文章中均根据实验来总结了一些结论。从实测结果与github/opencv中与RotatedRect和minAreaRect相关的issues来看,这两篇文章的结论可能只适用于部分opencv版本。

我使用博主OpenCV之RotatedRect基本用法和角度探究验证minAreaRect的代码在opencv4.5.5+VS2019的环境下验证的结论与博主得到的结论相反,代码如下:

实验结果如下图所示,左侧最后一组结果对应右侧图片。

angle in minAreaRect

综上所述,在使用RotatedRect和minAreaRect时,如果需要用到width/height/angle的规则,需要在代码中限定版本,或者根据实际值进行判断;否则当代码运行于其他版本的opencv时,原来设计的功能可能会失效。

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据

Fork me on GitHub