影醉阏轩窗

衣带渐宽终不悔,为伊消得人憔悴。
扩大
缩小

《图像处理实例》 之 透视变换

目的:将以下的图片转正显示

opencv自带的函数“透视变换”,但是有一点,四个交点的值我们是不知道的,有几种办法:

                  1.直接用鼠标去Image watch去查看四个交点的值。

                  2.用角点检测算法。。。我现在还没学到。

                  3.使用数学知识,求四条直线然后进行求取。

第一种很简单,分分钟实现了。第二种等以后学到再用。本文主要介绍第三种。

第一种方法实现:

 1 Point p1; // 左上角
 2     p1.x = 13;
 3     p1.y = 65;
 4     Point p2; // 右上角
 5     p2.x = 474;
 6     p2.y = 58;
 7     Point p3; // 左下角
 8     p3.x = 48;
 9     p3.y = 310;
10     Point p4; // 右下角
11     p4.x = 461;
12     p4.y = 317;
13 
14     // 透视变换
15     vector<Point2f> src_corners(4);
16     src_corners[0] = p1;
17     src_corners[1] = p2;
18     src_corners[2] = p3;
19     src_corners[3] = p4;
20     int width, height;
21     width = SourseImage.cols;
22     height = SourseImage.rows;
23 
24     vector<Point2f> dst_corners(4);
25     dst_corners[0] = Point(0, 0);
26     dst_corners[1] = Point(width, 0);
27     dst_corners[2] = Point(0, height);
28     dst_corners[3] = Point(width, height);
29 
30     // 获取透视变换矩阵
31     Mat warpmatrix = getPerspectiveTransform(src_corners, dst_corners);
32     warpPerspective(SourseImage, OutputImage, warpmatrix, SourseImage.size(), INTER_LINEAR);
33     imshow("123", SourseImage);

 效果图如下:就是手工输入有点牵强~~

第三种方法实现:

                             高斯滤波-->>灰度-->>二值化

形态学计算-->>反转

边缘检测:

 

 直线检测:(这个参数得适当的调整,不然效果很差)

 

数学方法求直线交点:

透视变换:

 

 代码:

  1 int main(int argc, char** argv)
  2 {
  3     SourseImage = imread("1.png");
  4     if (SourseImage.empty()) return -1;
  5     imshow("sourse", SourseImage);
  6     //-------------------预处理----------------------//
  7     GaussianBlur(SourseImage, MiddleImage, Size(3, 3), 3, 3);
  8     cvtColor(MiddleImage, MiddleImage, CV_BGR2GRAY);
  9     threshold(MiddleImage, MiddleImage, 0, 255, THRESH_BINARY | THRESH_OTSU);
 10     imshow("threImage", MiddleImage);
 11     //-------------------形态学操作-----------------//
 12     Mat kernel = getStructuringElement(MORPH_RECT, Size(27, 27));
 13     morphologyEx(MiddleImage, MiddleImage, MORPH_OPEN, kernel);
 14     morphologyEx(MiddleImage, MiddleImage, MORPH_OPEN, kernel);
 15     bitwise_not(MiddleImage, MiddleImage, Mat());
 16     imshow("morphology", MiddleImage);
 17     //----------------------边缘检测-----------------------------//
 18     vector<vector<Point>> contours;
 19     vector<Vec4i> hierarchy;
 20     Mat testImage = Mat::zeros(MiddleImage.size(), MiddleImage.type());
 21     findContours(MiddleImage, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE);
 22     for (size_t i = 0; i < contours.size(); i++)
 23     {
 24         drawContours(testImage, contours, i, Scalar(255, 255, 255), 1);
 25     }
 26     imshow("contours", testImage);
 27 
 28     int width = SourseImage.cols;
 29     int height = SourseImage.rows;
 30     //--------------------------霍夫直线检测------------------------//
 31     vector<Vec4i> lines;
 32     int accu = min(width*0.3, height*0.3);
 33     HoughLinesP(testImage, lines, 1, CV_PI / 360, accu, accu, 40);//参数最好用图片的长宽变换来的,容易移植
 34     Mat lineImage = Mat::zeros(MiddleImage.size(), MiddleImage.type());
 35     for (size_t i = 0; i < lines.size(); i++)
 36     {
 37         line(lineImage, Point(lines[i][0], lines[i][1]), Point(lines[i][2], lines[i][3]), Scalar(255, 255, 255), 1, 8, 0);
 38     }
 39     imshow("lines", lineImage);
 40     //-----------------查找线段对应的矩形边界------------------//
 41     Vec4i topline, bottomline, leftline, rightline;
 42     for (size_t i = 0; i < lines.size(); i++)
 43     {
 44         double roti = abs(lines[i][3] - lines[i][1]);
 45         //判断是平行X轴还是平行Y轴-->>|y2-y1|
 46         if (roti < SourseImage.cols / 3)//平行X轴(上下两条边)
 47         {
 48             if (lines[i][1] < SourseImage.rows / 2 && lines[i][3] < SourseImage.rows / 2) topline = lines[i];
 49             else bottomline = lines[i];
 50         }
 51         else//左右两条边
 52         {
 53             if (lines[i][0] < SourseImage.cols / 2 && lines[i][2] < SourseImage.cols / 2) leftline = lines[i];
 54             else rightline = lines[i];
 55         }
 56     }
 57     //--------------------计算四条线段的交点-----------------------//
 58     double b_top, b_bot, b_rit, b_lef;
 59     double k_top, k_bot, k_rit, k_lef;
 60     Point lef_top, rit_top, lef_bot, rit_bot;
 61     //直线斜率
 62     k_top = (topline[3] - topline[1]) / (topline[2] - topline[0]);
 63     k_bot = (bottomline[3] - bottomline[1]) / (bottomline[2] - bottomline[0]);
 64     k_rit = (rightline[3] - rightline[1]) / (rightline[2] - rightline[0]);
 65     k_lef = (leftline[3] - leftline[1]) / (leftline[2] - leftline[0]);
 66     //直线表达式因子,推到一遍就知道了
 67     b_top = topline[3] - k_top*topline[2];
 68     b_bot = bottomline[3] - k_bot*bottomline[2];
 69     b_rit = rightline[3] - k_rit*rightline[2];
 70     b_lef = leftline[3] - k_lef*leftline[2];
 71     //计算交点值
 72     lef_top.x = abs((b_top - b_lef) / (k_top - k_lef));
 73     rit_top.x = abs((b_top - b_rit) / (k_top - k_rit));
 74     lef_bot.x = abs((b_bot - b_lef) / (k_bot - k_lef));
 75     rit_bot.x = abs((b_bot - b_rit) / (k_bot - k_rit));
 76 
 77     lef_top.y = abs(k_top*lef_top.x + b_top);
 78     rit_top.y = abs(k_top*rit_top.x + b_top);
 79     lef_bot.y = abs(k_bot*lef_bot.x + b_bot);
 80     rit_bot.y = abs(k_bot*rit_bot.x + b_bot);
 81     //画出交点
 82     Mat lastImage = Mat::zeros(MiddleImage.size(), CV_8UC3);
 83     circle(lastImage, lef_top, 5, Scalar(0, 0, 255));
 84     circle(lastImage, rit_top, 5, Scalar(0, 0, 255));
 85     circle(lastImage, lef_bot, 5, Scalar(0, 0, 255));
 86     circle(lastImage, rit_bot, 5, Scalar(0, 0, 255));
 87     imshow("circle", lastImage);
 88     //-------------------------透视变换------------------------//
 89     //存储需要变换的四点
 90     vector<Point2f> srcPoint(4), dstPoint(4);
 91     srcPoint[0] = lef_top;
 92     srcPoint[1] = rit_top;
 93     srcPoint[2] = lef_bot;
 94     srcPoint[3] = rit_bot;
 95 
 96     dstPoint[0] = Point2f(0, 0);
 97     dstPoint[1] = Point2f(SourseImage.cols, 0);
 98     dstPoint[2] = Point2f(0, SourseImage.rows);
 99     dstPoint[3] = Point2f(SourseImage.cols, SourseImage.rows);
100 
101     Mat Change = getPerspectiveTransform(srcPoint,dstPoint);
102     warpPerspective(SourseImage, OutputImage, Change, OutputImage.size());
103     imshow("test",OutputImage);
104     waitKey(0);
105     return 0;
106 }

其实那个阈值化也可以自己手动去调节:

g_Value =95;

void on_AdaptThreshold(int, void*)
{
  int k = 2 * g_Value + 1;
  adaptiveThreshold(MiddleImage, OutputImage, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY, k, 0);
  imshow("AdaptThreshold", OutputImage);
}

 

 

参考:贾志刚opencv系列

posted on 2017-05-02 18:07  影醉阏轩窗  阅读(...)  评论(...编辑  收藏

导航

/* 线条鼠标集合 */ /* 鼠标点击求赞文字特效 */ //带头像评论