27、【opencv入门】轮廓查找与绘制(5)——最小外接矩形 三、粗略计算物体像素长宽 四、倾斜物体矫正提取

一、简介

1、最小外接矩形

轮廓最小外接矩形 --- minAreaRect(InputArray points);

1 CV_EXPORTS_W RotatedReect minAreaRect(InputArray points);

  points: 输入的二维点集, 可以填Mat类型或std::vector

  返回值: RotatedRect类矩形对象, 外接旋转矩形主要成员有center、size、 angle、points

在opencv中,坐标的原点在左上角,与x轴平行的方向为角度为0,逆时针旋转角度为负,顺时针旋转角度为正。而RotatedRect类是以矩形的哪一条边与x轴的夹角作为角度的呢?angle 是水平轴(x轴)逆时针旋转,与碰到的第一个边的夹角,而opencv默认把这个边的边长作为width,angle的取值范围必然是负的 。

二、轮廓最小外接矩形的绘制

 1 //轮廓最小外接矩形的绘制
 2 #include "opencv2/opencv.hpp"
 3 
 4 using namespace cv;
 5 
 6 int main()
 7 {    
 8     //轮廓最小外接矩形的绘制
 9     Mat srcImg = imread("1.png");
10     Mat dstImg = srcImg.clone();
11     cvtColor(srcImg, srcImg, CV_BGR2GRAY);
12     threshold(srcImg, srcImg, 100, 255, CV_THRESH_BINARY); //二值化
13     imshow("threshold", srcImg);
14 
15     vector<vector<Point>> contours;
16     vector<Vec4i> hierarcy;
17     findContours(srcImg, contours, hierarcy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
18     vector<Rect> boundRect(contours.size());  //定义外接矩形集合
19     vector<RotatedRect> box(contours.size()); //定义最小外接矩形集合
20     Point2f rect[4];
21     for(int i=0; i<contours.size(); i++)
22     {
23         box[i] = minAreaRect(Mat(contours[i]));  //计算每个轮廓最小外接矩形
24         boundRect[i] = boundingRect(Mat(contours[i]));
25         circle(dstImg, Point(box[i].center.x, box[i].center.y), 5, Scalar(0, 255, 0), -1, 8);  //绘制最小外接矩形的中心点
26         box[i].points(rect);  //把最小外接矩形四个端点复制给rect数组
27         rectangle(dstImg, Point(boundRect[i].x, boundRect[i].y), Point(boundRect[i].x + boundRect[i].width, boundRect[i].y + boundRect[i].height), Scalar(0, 255, 0), 2, 8);
28         for(int j=0; j<4; j++)
29         {
30             line(dstImg, rect[j], rect[(j+1)%4], Scalar(0, 0, 255), 2, 8);  //绘制最小外接矩形每条边
31         }
32     }    
33     imshow("dst", dstImg);
34     waitKey(0);
35     return 0;
36 }
 1 //粗略计算物体的像素长宽
 2 #include "opencv2/opencv.hpp"
 3 #include<iostream>
 4 
 5 using namespace std;
 6 using namespace cv;
 7 
 8 int main()
 9 {    
10     Mat srcImg = imread("1.jpg");
11     imshow("src", srcImg);
12     Mat dstImg = srcImg.clone();
13     medianBlur(srcImg, srcImg, 5);
14     GaussianBlur(srcImg, srcImg, Size(3, 3), 0, 0);
15     cvtColor(srcImg, srcImg, CV_BGR2GRAY);
16     threshold(srcImg, srcImg, 100, 255, CV_THRESH_BINARY_INV); //INV是因为背景白色,物体黑色,需要反转一下
17     imshow("threshold", srcImg);
18 
19     vector<vector<Point>> contours;
20     vector<Vec4i> hierarcy;
21     
22     findContours(srcImg, contours, hierarcy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
23     cout<<"num="<<contours.size()<<endl;
24     vector<Rect> boundRect(contours.size());
25     vector<RotatedRect> box(contours.size());
26     Point2f rect[4];
27     for(int i=0; i<contours.size(); i++)
28     {
29         box[i] = minAreaRect(Mat(contours[i]));    
30         boundRect[i] = boundingRect(Mat(contours[i]));
31         cout<<box[i].angle<<endl; 
32         cout<<box[i].center<<endl; 
33         cout<<box[i].size.width<<endl; 
34         cout<<box[i].size.height<<endl; 
35         circle(dstImg, Point(box[i].center.x, box[i].center.y), 5, Scalar(0, 255, 0), -1, 8);
36         
37         //绘制外接矩形和    最小外接矩形(for循环)
38         rectangle(dstImg, Point(boundRect[i].x, boundRect[i].y), Point(boundRect[i].x + boundRect[i].width, boundRect[i].y + boundRect[i].height), Scalar(0, 255, 0), 2, 8);
39         box[i].points(rect);//把最小外接矩形四个端点复制给rect数组
40         for(int j=0; j<4; j++)
41         {
42             line(dstImg, rect[j], rect[(j+1)%4], Scalar(0, 0, 255), 2, 8);
43         }
44 
45         char width[20], height[20];
46         sprintf(width, "width=%0.2f", box[i].size.width);
47         sprintf(height, "height=%0.2f", box[i].size.height);
48         putText(dstImg, width, Point(235, 260), CV_FONT_HERSHEY_COMPLEX_SMALL, 0.85, Scalar(0, 255, 0));
49         putText(dstImg, height, Point(235, 285), CV_FONT_HERSHEY_COMPLEX_SMALL, 0.85, Scalar(0, 255, 0));
50     
51     }    
52     imshow("dst", dstImg);
53     waitKey(0);
54     return 0; 
55 }

四、倾斜物体矫正提取

 1 //倾斜物体的矫正提取
 2 #include "opencv2/opencv.hpp"
 3 #include<iostream>
 4 
 5 using namespace std;
 6 using namespace cv;
 7 
 8 int main()
 9 {    
10     Mat srcImg = imread("1.jpg");
11     imshow("src", srcImg);
12     Mat dstImg = srcImg.clone();
13     GaussianBlur(srcImg, srcImg, Size(3, 3), 0, 0);
14     cvtColor(srcImg, srcImg, CV_BGR2GRAY);
15     Canny(srcImg, srcImg, 100, 200);//因为原图比较复杂,所以需要将canny的值调大,去除不想要的成分
16     //threshold(srcImg, srcImg, 100, 255, CV_THRESH_BINARY_INV); //二值化也可以实现canny效果,不过在本例中杂絮较多
17     imshow("canny", srcImg);
18     Mat element = getStructuringElement(MORPH_RECT, Size(11, 11), Point(-1, -1)); //定义结构元素
19     dilate(srcImg, srcImg, element); //膨胀
20     imshow("dilate", srcImg);
21     erode(srcImg, srcImg, element);
22     imshow("erode", srcImg);
23 
24     vector<vector<Point>> contours;
25     vector<Vec4i> hierarcy;
26     findContours(srcImg, contours, hierarcy, CV_RETR_TREE, CV_CHAIN_APPROX_NONE);
27     vector<Rect> boundRect(contours.size());
28     vector<RotatedRect> box(contours.size());
29     Point2f rect[4];
30     for(int i=0; i<contours.size(); i++)
31     {
32         box[i] = minAreaRect(Mat(contours[i]));    
33         boundRect[i] = boundingRect(Mat(contours[i]));
34 
35         if(box[i].size.width < 100 || box[i].size.height<100)//筛选
36             continue;
37         rectangle(dstImg, Point(boundRect[i].x, boundRect[i].y), Point(boundRect[i].x + boundRect[i].width, boundRect[i].y + boundRect[i].height), Scalar(0, 255, 0), 2, 8);
38         circle(dstImg, Point(box[i].center.x, box[i].center.y), 5, Scalar(0, 255, 0), -1, 8);
39         box[i].points(rect);        
40         for(int j=0; j<4; j++)
41         {
42             line(dstImg, rect[j], rect[(j+1)%4], Scalar(0, 0, 255), 2, 8);
43         }
44 
45         float angle;
46         cout<<"angle="<<box[i].angle<<endl;
47         angle = box[i].angle;
48         char width[20], height[20];     
49         sprintf(width, "width=%0.2f", box[i].size.width);
50         sprintf(height, "height=%0.2f", box[i].size.height);
51         putText(dstImg, width, Point(195, 260), CV_FONT_HERSHEY_COMPLEX_SMALL, 0.85, Scalar(0, 255, 0));
52         putText(dstImg, height, Point(190, 285), CV_FONT_HERSHEY_COMPLEX_SMALL, 0.85, Scalar(0, 255, 0));
53         imshow("temp", dstImg);
54 
55         //利用仿射变换进行旋转        另一种方法,透视变换
56         if (0< abs(angle) && abs(angle)<=45)  
57             angle = angle;//负数,顺时针旋转
58         else if (45< abs(angle) && abs(angle)<90) 
59             angle = 90 -  abs(angle);//正数,逆时针旋转
60         Point2f center = box[i].center;  //定义旋转中心坐标
61         double angle0 = angle;
62         double scale = 1;
63         Mat roateM = getRotationMatrix2D(center, angle0, scale);  //获得旋转矩阵,顺时针为负,逆时针为正
64         warpAffine(dstImg, dstImg, roateM, dstImg.size()); //仿射变换
65 
66         //保存二维码
67         int x0=0, y0=0, w0=0, h0=0;
68         x0 = boundRect[i].x; 
69         y0 = boundRect[i].y; 
70         w0 = boundRect[i].width; 
71         h0 = boundRect[i].height; 
72         Mat ROI = dstImg(Rect(x0, y0, w0, h0));
73         imwrite("F://1.jpg", ROI);
74     }    
75     imshow("dst", dstImg);
76     waitKey(0);
77     return 0;
78 }