opencv 最小外接矩阵旋转角度

实验中使用到最小外接矩阵角度的内容,写博客记录。

本篇主要参考了如下四个博客:

                       https://blog.csdn.net/u013925378/article/details/84563011

                        https://blog.csdn.net/weixin_40647819/article/details/80884594

                        https://www.cnblogs.com/little-monkey/p/7429579.html

                        https://blog.csdn.net/bemy1008/article/details/86237961

第一篇博客主要介绍opencv外接矩阵boundingRect与最小外接矩阵minAreaRect的用法区别,后三篇博客结合可对最小外接旋转角度有较为清晰的认识。

下面对知识点做总结记录:

1.外接矩阵与最小外接矩阵的差别

Rect boundingRect(InputArray points)得到包覆此轮廓的最小正矩形,RotatedRect minAreaRect(InputArray points)得到包覆轮廓的最小矩阵。具体可以查阅第一个链接博客

2.RotatedRect有三个属性1)矩形中心点(质心)2)边长(长和宽)3)旋转角度(返回的值是角度值而非弧度值)

   旋转角度的范围是[-90,0),当矩形水平或者竖直时均返回-90。(下图来源上面链接2博客)

           在opencv中,坐标的原点在左上角,与x轴平行的方向角度为0,逆时针旋转角度为负,顺时针旋转角度为正(在x轴和y轴的            象限里的角度为正的原则吧)。minAreaRect类中的角度值是水平轴(x轴)逆时针旋转与碰到的第一个边的夹角。因此,            角度值必然是负值,取值范围为[-90,0)。同时,以这样的旋转方式,碰到的第一个边被定义为width。由于是以这样的方              式判断width,因此存在width<height的情况。

3.  Mat getRotationMatrix2D(Point2f center, double angle, double scale)(注意它中的角度与最小外接矩阵角度的差异)

        该函数中的角度:如果该角度为正值,则为逆时针旋转

                                     如果该角度为负值,则为顺时针旋转

下面是一个测试代码,主要是展现上边三个函数的使用方法:

#include <iostream>
#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

RNG rng(12345);
int main()
{
        Mat srcImg = imread("timg.jpg");
	Mat dstImg = srcImg.clone();
	cvtColor(srcImg, srcImg, CV_BGR2GRAY);
	threshold(srcImg, srcImg, 0, 255.0, THRESH_BINARY_INV | CV_THRESH_OTSU);
	Mat element = getStructuringElement(MORPH_RECT, Size(11, 11), Point(-1, -1)); //定义结构元素
	dilate(srcImg, srcImg, element);
        
        vector<vector<Point>> contours;
	vector<Vec4i> hierarcy;
	findContours(srcImg, contours, hierarcy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE, Point(0, 0));
	Rect boundRect;//只绘制最大轮廓对应的外接矩阵
	RotatedRect box;//只绘制最大轮廓对应的最小外接矩阵
       
        Point2f rect[4];
	Mat drawing = Mat::zeros(srcImg.size(), CV_8UC3);
	int len = 0;
	for (int i = 0; i<contours.size(); i++)
	{
		//绘制轮廓
		/*Scalar color = Scalar(rng.uniform(0, 256), rng.uniform(0, 256), rng.uniform(0, 256));
		drawContours(drawing, contours, (int)i, color, 2, 8, hierarcy);*/
		cout << contours[i].size() << endl;
		if (contours[i].size()>len)
		{
			len = contours[i].size();
			box = minAreaRect(Mat(contours[i]));//最小外接矩阵
			boundRect = boundingRect(Mat(contours[i]));//外接矩阵
		}
	}
	//绘制外接矩阵绿色框绘制
	rectangle(dstImg, Point(boundRect.x, boundRect.y), Point(boundRect.x + boundRect.width, boundRect.y + boundRect.height), Scalar(0, 255, 0), 2, 8);	
	box.points(rect);
	//绘制最小外接矩阵红色框绘制
	for (int j = 0; j < 4; j++)
	{
		line(dstImg, rect[j], rect[(j + 1) % 4], Scalar(0, 0, 255), 2, 8);//
	}
	imshow("外接矩阵", dstImg);

	//最小外接矩阵的角度,根据角度对最小外接矩阵旋转
	float boxangle = box.angle;
	cout << boxangle << endl;
	cout << "width:" << box.size.width << '\t' << "height:" << box.size.height << endl;
	//根据角度对图像进行旋转
	if (0< abs(boxangle) && abs(boxangle) <= 45)
		boxangle = boxangle;
	else if (45< abs(boxangle) && abs(boxangle)<90)
		boxangle = 90 - abs(boxangle);
	Point2f center = box.center;  //定义旋转中心坐标
	double angle0 = boxangle;
	double scale = 1;
	Mat roateM = getRotationMatrix2D(center, angle0, scale);//获得旋转矩阵,顺时针为负,逆时针为正
	warpAffine(dstImg, dstImg, roateM, dstImg.size());//仿射变换
	imshow("根据角度旋转之后图像", dstImg);
	waitKey(0);
	return 0;
       
}

 对下面图像(图像来源网络)使用上述方法得到其外接矩阵(绿色)、最小外接矩阵(红色)、及其根据最小外接矩阵角度使用仿射变换获得的旋转图像。

结果图:

 

文中若有错误或不妥之处,还望指出,以便共同学习!

 

 

 

 

 

 

 

 

  • 6
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值