OpenCV 获取倾斜矩形ROI图像

OpenCV 外接矩形与最小外接矩形

          由于项目的需要,在找目标时需要将目标图像“抠”下来,作为下一步骤的输入图像。当目标区域的最小外接矩形没有倾斜时还好,直接用OpenCV的cv::Rect(关于没有倾斜角度矩形ROI的提取,见:图像处理之定位_yishuihanq的博客-CSDN博客_图像定位处理),取ROI就可以了;但是如果目标区域的最小外接矩形有倾斜角度时,就不好搞了,OpenCV中没有这样的函数,需要自己想办法去提取。

       需要将图1中的目标“书”,提取出来,提取后的结果图像,如图2。

OpenCV 获取倾斜矩形ROI图像_第1张图片

图1 原图src

OpenCV 获取倾斜矩形ROI图像_第2张图片

 图2 ROI图像

 对此有以下几种方法:

case 1、根据目标ROI的倾斜角度angle,对原图进行旋转,再提取出ROI区域;

case 2、获取目标ROI的外接矩形rect,对外接矩形rect 旋转angle角度,再提取出ROI区域;

步骤:

1、求得书本的轮廓;

2、获取书本轮廓的最小外接矩形rotatedRect(主要是获取旋转中心、旋转角度);

3、进行旋转校正,提取目标区域。


	#if(1)
		//方法1:对整个大图进行旋转,然后提取目标ROI.
		cv::Mat dstTemp1;
		cv::Mat result1;
		cv::Size2f rotatedRectSize = rotatedRect.size;
		//cv::Size rect_size = minRect.size();
		cv::Point2f center = rotatedRect.center;//最小外接矩形中心点坐标
		//获取旋转矩阵,绕中心进行旋转. m_resize缩放倍数
		cv::Mat M = cv::getRotationMatrix2D(center, rotatedRect.angle, 1);
		cv::warpAffine(src, dstTemp1, M, src.size());
		//提取ROI
		result1 = dstTemp1( cv::Rect(center.x - (rotatedRectSize.width / 2),
			center.y - (rotatedRectSize.height / 2),
			rotatedRectSize.width, rotatedRectSize.height) );

		cv::imwrite("../dstTemp1.jpg", dstTemp1);
		cv::namedWindow("dstTemp1", 0);
		cv::imshow("dstTemp1", dstTemp1);

		cv::imwrite("../result1.jpg", result1);
		cv::namedWindow("result1", 0);
		cv::imshow("result1", result1);
		cv::waitKey(0);
	#endif

case 2:

    #if(1)
		//方法2:对目标ROI区域倾斜矩形的外接矩形进行旋转,然后提取目标ROI.
		cv::Rect boundingRect = rotatedRect.boundingRect();//返回包含旋转矩形的最小矩形
		cv::Mat newSrc = srcCopy(boundingRect);
		//ROI区域倾斜矩形的外接矩形,的旋转中心.
		cv::Point newCenter;
		newCenter.x = rotatedRect.center.x - boundingRect.x;
		newCenter.y = rotatedRect.center.y - boundingRect.y;
		//获取旋转矩阵,绕中心进行旋转. m_resize缩放倍数
		cv::Mat newM2 = cv::getRotationMatrix2D(newCenter, rotatedRect.angle, 1);
		cv::Mat newDstTemp2;
		cv::warpAffine(newSrc, newDstTemp2, newM2, newSrc.size());
		//提取ROI
		cv::Mat newResult2;
		newResult2 = ( newDstTemp2(cv::Rect(newCenter.x - (rotatedRect.size.width / 2),
			newCenter.y - (rotatedRect.size.height / 2),
			rotatedRect.size.width, rotatedRect.size.height)) );

		//cv::putText(newResult2, std::to_string(newResult2.size()),
		//	cv::Point(160, 100),
		//	cv::FONT_HERSHEY_PLAIN, 6, cv::Scalar(0, 0, 255), 10);
		//方法2:对目标ROI区域倾斜矩形的外接矩形进行旋转,然后提取目标ROI.
		cv::imwrite("../newDstTemp2.jpg", newDstTemp2);
		cv::namedWindow("newDstTemp2", 0);
		cv::imshow("newDstTemp2", newDstTemp2);
		//cv::waitKey(0);
		cv::imwrite("../newResult2.jpg", newResult2);
		cv::namedWindow("newResult2", 0);
		cv::imshow("newResult2", newResult2);
		cv::waitKey(0);
	#endif

最终结果图像如下:

OpenCV 获取倾斜矩形ROI图像_第3张图片

OpenCV 获取倾斜矩形ROI图像_第4张图片

 case 3:

// 3.OpenCV中的方法
//contours.at(i):目标轮廓的最小外接矩形 
cv::RotatedRect rect = cv::minAreaRect(contours.at(i));
cv::Mat M, rotated;
//cv::Mat cropped;
// get angle and size from the bounding box
double angle = static_cast(rect.angle);
cv::Size rect_size = rect.size;
if (angle < -45.0) 
{
	angle += 90.0;
	cv::swap(rect_size.width, rect_size.height);
}
// get the rotation matrix
M = getRotationMatrix2D(rect.center, angle, 1.0);
// perform the affine transformation
warpAffine(src, rotated, M, src.size(), cv::INTER_CUBIC);
// crop the resulting image
getRectSubPix(rotated, rect_size, rect.center, cropped);

//cv::imwrite("../testImage/RotatedRectCropped.jpg", cropped);
cv::namedWindow("crop", 0);
cv::imshow("crop", cropped);
cv::waitKey(0);

OpenCV 获取倾斜矩形ROI图像_第5张图片

 

 cv::boxpoints函数的作用:获取矩形的四个顶点坐标。

# 获取最小外接矩阵,中心点坐标,宽高,旋转角度
cv::RotatedRect rect = cv::minAreaRect(contours)
# 获取矩形四个顶点坐标,浮点型
std::vector boxPts;
boxPts = cv::boxPoints(rect)
# 取整
boxPts = np.int0(boxPts)

在OpenCV的坐标体系下,纵坐标最小的是top_point,纵坐标最大的是bottom_point, 横坐标最小的是left_point,横坐标最大的是right_point。


===================================================================
-.-.-.-.-以下内容原文链接:https://blog.csdn.net/Dorwin666/article/details/109518925-.-.-.-.-.

OpenCV中minAreaRect() 函数和RotatedRect类参数详解

RotatedRect minAreaRect(InputArray points)

RotatedRect表示平面上的旋转矩形

class CV_EXPORTS RotatedRect
{
public:
    //构造函数
    RotatedRect();
    RotatedRect(const Point2f& center, const Size2f& size, float angle);//矩形中心点(质心)、边长(长和宽)、旋转角度
    RotatedRect(const CvBox2D& box);
    void points(Point2f pts[]) const;//!返回矩形的4个顶点
    Rect boundingRect() const; //返回包含旋转矩形的最小矩形
    operator CvBox2D() const;    //!转换到旧式的cvbox2d结构
    Point2f center; //矩形的质心
    Size2f size;   //矩形的边长
    float angle;  //旋转角度,当角度为0、90、180、270等时,矩形就成了一个直立的矩形
};

       这个类中包含了外接矩形的中心center、大小size以及角度angle,首先center是很好理解的,就是这个矩形的中心点位置,而angle代表的是旋转角度,size包含一个width和一个height,代表的是矩形的宽和高。
       矩形的Width与Height定义:矩形坐标系中X轴逆时针旋转,碰到的第一条边为Width,另一条边为Height,其中矩形坐标系的原点为图像坐标系下矩形四个顶点中y值最大的点,如图所示:

OpenCV 获取倾斜矩形ROI图像_第6张图片

根据上图,说明以下几点:

  1. Opencv采用通用的图像坐标系,左上角为原点O(0,0),X轴向右递增,Y轴向下递增,单位为像素。
  2. 矩形4个顶点位置的确定,是理解其它各变量的基础,其中p[0]点是关键。

顶点p[0]的位置可以这样理解:

ⓐ 如果没有边与坐标轴平行,则Y坐标最大的点为p[0]点,如矩形(2)(3)(4);

ⓑ 如果有边与坐标轴平行,则有两个Y坐标最大的点。此时,左侧的点为p[0]点。如矩形(1)。

即:Y坐标最大的点为p[0]。如果有两个最大的Y坐标,则左侧点(X坐标较小)为p[0]。

  1. p[0]~p[3]按顺时针方向依次排列。
  2. p[0]到p[3]之间的距离为宽width,其邻边为高height。
  3. 角度angle,是以矩形坐标系的X轴方向相同的射线为始边,按逆时针方向旋转到宽边Width所经过的角度,由于opencv定义顺时针方向为正,因此angle 取负值,取值范围为(-90, 0]。
  4. 中心点center为矩形对角线的交点。

         但是opencv版本从4.1以后minAreaRect()返回的顶点和角的定义就改变了,p[0]定义为四个顶点中x值最小点,然后p[1]、p[2]、p[3]按顺时针旋转顺序定义,角度为90°减去上个版本原定义角度。width与height的定义应该没变,p[0]与p[1]之间的长度为height,另一边为width。额,测试了三个图型后得到的结论貌似是这样,还有待进一步验证。。。

-.-.-.-.-以上内容原文链接:https://blog.csdn.net/Dorwin666/article/details/109518925-.-.-.-.-.
====================================================================

你可能感兴趣的:(OpenCV,图像处理,c++,opencv,visual,studio)