zoukankan      html  css  js  c++  java
  • 《图像处理实例》 之 透视变换

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

    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系列

  • 相关阅读:
    github设置添加SSH
    解决方案 git@github.com出现Permission denied (publickey)
    Shell 获取进程号 规格严格
    转线程堆栈获取 规格严格
    NTP搭建(原创) 规格严格
    Ntp完整说明(转载) 规格严格
    JavaAgent(转载) 规格严格
    Location of javaagent jar in bootclasspath 规格严格
    Manifest(转) 规格严格
    分析一下shell(转) 规格严格
  • 原文地址:https://www.cnblogs.com/wjy-lulu/p/6797478.html
Copyright © 2011-2022 走看看