这里采用第一种方法
待处理得图
1 #include <opencv2/opencv.hpp> 2 #include <iostream> 3 #include <math.h> 4 5 using namespace cv; 6 using namespace std; 7 8 Mat src, gray_src, dst; 9 int threshold_value = 100; 10 int max_level = 255; 11 12 const char* output_win = "Contours Result"; 13 const char* roi_win = "Final Result"; 14 15 void FindROI(int, void*); 16 void Check_Skew(int, void*); 17 18 int main(int argc, char** argv) { 19 src = imread("timg.jpg"); 20 if (src.empty()) { 21 printf("could not load image...\n"); 22 return -1; 23 } 24 namedWindow("input image", CV_WINDOW_AUTOSIZE); 25 imshow("input image", src); 26 namedWindow(output_win, CV_WINDOW_AUTOSIZE); 27 Check_Skew(0, 0); 28 // namedWindow(roi_win, CV_WINDOW_AUTOSIZE); 29 //createTrackbar("Threshold:", output_win, &threshold_value, max_level, FindROI); 30 // FindROI(0, 0); 31 32 waitKey(0); 33 return 0; 34 } 35 36 //将原图放正,如需切边还需执行另一个函数一次(因为不能对斜着的图直接切边) 37 void Check_Skew(int, void*) { 38 Mat canny_output; 39 cvtColor(src, gray_src, COLOR_BGR2GRAY); 40 Canny(gray_src, canny_output, threshold_value, threshold_value * 2, 3, false); 41 42 vector<vector<Point>> contours; 43 vector<Vec4i> hireachy; 44 findContours(canny_output, contours, hireachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0)); 45 Mat drawImg = Mat::zeros(src.size(), CV_8UC3); 46 float maxw = 0; 47 float maxh = 0; 48 double degree = 0; 49 50 //获取最大旋转矩形的尺寸 51 for (size_t t = 0; t < contours.size(); t++) { 52 RotatedRect minRect = minAreaRect(contours[t]); 53 degree = abs(minRect.angle); 54 if (degree > 0) {//判断是否有旋转 55 maxw = max(maxw, minRect.size.width); 56 maxh = max(maxh, minRect.size.height); 57 } 58 } 59 RNG rng(12345); 60 61 //根据最大旋转矩形的尺寸,判断并画出来轮廓同时得到旋转角度 62 for (size_t t = 0; t < contours.size(); t++) { 63 RotatedRect minRect = minAreaRect(contours[t]); 64 if (maxw == minRect.size.width && maxh == minRect.size.height) {//判断是否是最大边界 65 degree = minRect.angle+90;//判断得是0点到height边的角度,逆时针为负,即使正放也有-90°所以要+90 66 Point2f pts[4]; 67 minRect.points(pts); 68 Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)); 69 for (int i = 0; i < 4; i++) { 70 line(drawImg, pts[i], pts[(i + 1) % 4], color, 2, 8, 0); 71 } 72 } 73 } 74 printf("max contours width : %f\n", maxw); 75 printf("max contours height : %f\n", maxh); 76 printf("max contours angle : %f\n", degree); 77 imshow(output_win, drawImg); 78 79 //旋转成正的 80 Point2f center(src.cols / 2, src.rows / 2);//旋转中心 81 Mat rotm = getRotationMatrix2D(center, degree, 1.0);//函数调用形式: 82 //Mat getRotationMatrix2D(Point2f center,表示旋转的中心点 83 //double angle, 表示旋转的角度 84 //double scale) 图像缩放因子 85 Mat dst; 86 warpAffine(src, dst, rotm, src.size(), INTER_LINEAR, 0, Scalar(255, 255, 255));//仿射变换 87 imshow("Correct Image", dst); 88 } 89 90 //无旋转的处理函数,对已经放正的函数切边 91 void FindROI(int, void*) { 92 93 //提取边缘 94 cvtColor(src, gray_src, COLOR_BGR2GRAY); 95 Mat canny_output; 96 Canny(gray_src, canny_output, threshold_value, threshold_value * 2, 3, false); 97 98 //绘制轮廓 99 vector<vector<Point>> contours; 100 vector<Vec4i> hireachy; 101 findContours(canny_output, contours, hireachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0)); 102 103 //画出最大轮廓的最小外接矩形 104 int minw = src.cols*0.75; 105 int minh = src.rows*0.75; 106 RNG rng(12345); 107 Mat drawImage = Mat::zeros(src.size(), CV_8UC3); 108 Rect bbox; 109 for (size_t t = 0; t < contours.size(); t++) { 110 RotatedRect minRect = minAreaRect(contours[t]);//获取轮廓t的最小外接矩形,RotatedRect旋转矩形,可以设置矩形中心,矩形长宽,旋转角度 111 float degree = abs(minRect.angle);//获取旋转角度 112 if (minRect.size.width > minw && minRect.size.height > minh && minRect.size.width < (src.cols - 5)) {//轮廓筛选,选出最大的外接矩形 113 printf("current angle : %f\n", degree); 114 Point2f pts[4]; 115 minRect.points(pts);//将最大的外接矩形的四个点赋给pts 116 bbox = minRect.boundingRect();//外接正矩形边界 117 Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)); 118 for (int i = 0; i < 4; i++) { 119 line(drawImage, pts[i], pts[(i + 1) % 4], color, 2, 8, 0); 120 } 121 } 122 } 123 imshow(output_win, drawImage); 124 125 //用找到的最小外接矩形截取图像 126 if (bbox.width > 0 && bbox.height > 0) { 127 Mat roiImg = src(bbox);//用括号内的范围截取ROI区域 128 imshow(roi_win, roiImg); 129 } 130 return; 131 }