RotateRect(旋转矩形)的倾斜旋转变换矫正
在Opencv中的图像处理中,经常要用到minAreaRect()函数求最小外接矩形,该函数的返回值就是一个RotatedRect类对象。
RotatedRect类定义如下:
class CV_EXPORTS RotatedRect { public: //! various constructors RotatedRect(); RotatedRect(const Point2f& center, const Size2f& size, float angle); RotatedRect(const CvBox2D& box); //! returns 4 vertices of the rectangle void points(Point2f pts[]) const; //! returns the minimal up-right rectangle containing the rotated rectangle Rect boundingRect() const; //! conversion to the old-style CvBox2D structure operator CvBox2D() const; Point2f center; //< the rectangle mass center Size2f size; //< width and height of the rectangle float angle; //< the rotation angle. When the angle is 0, 90, 180, 270 etc., the rectangle becomes an up-right rectangle. };
类中定义了矩形的中心点center、尺寸size(包括width、height)、旋转角度angle共3个成员变量;
points()函数用于求矩形的4个顶点,boundingRect()函数求包含最小外接矩形的,与坐标轴平行(或垂直)的最小矩形。
正确理解这些变量在图形中的对应关系,是正确应用该类的基础。先上示意图:
根据上图,说明以下几点:
1. Opencv采用通用的图像坐标系,左上角为原点O(0,0),X轴向右递增,Y轴向下递增,单位为像素。
2. 矩形4个顶点位置的确定,是理解其它各变量的基础,其中p[0]点是关键。
顶点p[0]的位置可以这样理解:
ⓐ 如果没有对边与Y轴平行,则Y坐标最大的点为p[0]点,如矩形(2)(3)(4);
ⓑ 如果有对边与Y轴平等,则有两个Y坐标最大的点,此时,取左侧的点为p[0]点,如矩形(1)。
3. p[0]~p[3]按顺时针次序依次排列。
4. p[0]到p[3]之间的距离宽width,其邻边为高height。
5. 角度angle以穿过p[0],且平行于X轴的直线为始边,按逆时针方向旋转到宽边p[0]p[3]所经过的角度,
取负值,取值范围为(-90, 0]。
6. 中心点center为矩形对角线的交点。
#include<opencv2/opencv.hpp> using namespace std; void main(){ string path = ""; Mat img = imread(path); Mat img_gray; cvtColor(img,img_gray,COLOR_BGR2GRAY); Mat thresh_img(img.size(),CV_8UC1); threshold(img_gray, thresh_img,230,255,THRESH_BINARY_INV); imshow("thresh",thresh_img); waitKey(); vector<vector<Point>> contours; findContours(thresh_img, contours,CV_RET_EXTERNAL,CV_CHAIN_APPROX_NONE); RotatedRect mr = minAreaRect(Mat(contours[0])); Mat Drawing(img.size(), img.type(), Scalar(255,255,255)); Point2f vectpoint[4]; mr.points(vectpoint); for (int i = 0; i < 4; i++){ line(Drawing, vectpoint[(i+1)%4], Scalar(255,0,0),2); } imshow("drawing",Drawing); waitkey(); float angle = 0.0; Size si = mr.size; if (mr.size.width <= mr.size.height){ angle = mr.angle + 90; int tm = si.width; si.width = si.height; si.height = tm; //swap(si.width, si.height); } else { angle = mr.angle; } Mat rotmat = getRotationMatrix2D(mr.center, angle, 1); Mat deal_img; warpAffine(img, deal_img, rotmat, img.size(), CV_INTER_CUBIC); imshow("deal_img",deal_img); waitkey(); gerRectSubpix(deal_img, si, mr.center, rRect); imshow("截取的的矩形区域",rRect); waitKey(); }
Talk is cheap. Show me the code