opencv透視變換


opencv透視變換
實現透視變換
目標:
在這篇教程中你將學到:
1、如何進行透視變化
2、如何生存透視變換矩陣
理論:
什么是透視變換:
1、 透視變換(Perspective Transformation)是將圖片投影到一個新的視平面(Viewing Plane),也稱作投影映射(Projective Mapping)。
2、換算公式

u,v是原始圖片左邊,對應得到變換后的圖片坐標x,y,其中
變換矩陣可以拆成4部分,表示線性變換,比如scaling,shearing和ratotion。用於平移,產生透視變換。所以可以理解成仿射等是透視變換的特殊形式。經過透視變換之后的圖片通常不是平行四邊形(除非映射視平面和原來平面平行的情況)。

重寫之前的變換公式可以得到:

所以,已知變換對應的幾個點就可以求取變換公式。反之,特定的變換公式也能新的變換后的圖片。簡單的看一個正方形到四邊形的變換:
變換的4組對應點可以表示成:

根據變換公式得到:

定義幾個輔助變量:

都為0時變換平面與原來是平行的,可以得到:

不為0時,得到:

求解出的變換矩陣就可以將一個正方形變換到四邊形。反之,四邊形變換到正方形也是一樣的。於是,我們通過兩次變換:四邊形變換到正方形+正方形變換到四邊形就可以將任意一個四邊形變換到另一個四邊形。

代碼:
# include  "opencv2/highgui.hpp"
# include  "opencv2/imgproc.hpp"
# include  <iostream >
# include  <stdio.h >
using  namespace  cv;
using  namespace  std;
/**  @function  main  */
int  main(  int  argc,  char * *  argv  )
{
             cv : :Mat src = cv : :imread(  "test.jpg", 0);
                  if ( !src.data)
                                  return  0;
                vector <Point > not_a_rect_shape;
                not_a_rect_shape.push_back(Point( 122, 0));
                not_a_rect_shape.push_back(Point( 814, 0));
                not_a_rect_shape.push_back(Point( 22, 540));
                not_a_rect_shape.push_back(Point( 910, 540));
                  // For debugging purposes, draw green lines connecting those points
                  // and save it on disk
                 const Point * point = &not_a_rect_shape[ 0];
                 int n = ( int )not_a_rect_shape.size();
                Mat draw = src.clone();
                polylines(draw, &point, &n, 1true, Scalar( 0, 255, 0), 3, CV_AA);
                imwrite(  "draw.jpg", draw);
                  //  topLeft, topRight, bottomRight, bottomLeft
                cv : :Point2f src_vertices[ 4];
                src_vertices[ 0] = not_a_rect_shape[ 0];
                src_vertices[ 1] = not_a_rect_shape[ 1];
                src_vertices[ 2] = not_a_rect_shape[ 2];
                src_vertices[ 3] = not_a_rect_shape[ 3];

                Point2f dst_vertices[ 4];
                dst_vertices[ 0] = Point( 0, 0);
                dst_vertices[ 1] = Point( 960, 0);
                dst_vertices[ 2] = Point( 0, 540);
                dst_vertices[ 3] = Point( 960, 540);
                Mat warpMatrix = getPerspectiveTransform(src_vertices, dst_vertices);
                cv : :Mat rotated;
                warpPerspective(src, rotated, warpMatrix, rotated.size(), INTER_LINEAR, BORDER_CONSTANT);
                  // Display the image
                cv : :namedWindow(  "Original Image");
                cv : :imshow(  "Original Image",src);
                cv : :namedWindow(  "warp perspective");
                cv : :imshow(  "warp perspective",rotated);
                imwrite(  "result.jpg",src);
                cv : :waitKey();
                  return  0;
}
代碼解釋:
1、獲取圖片,如果輸入路徑為空的話程序直接退出
  cv : :Mat src = cv : :imread(  "test.jpg", 0);
                  if ( !src.data)
                                  return  0;
2、定義邊界點,輸入到std::vector數據結構中。注意這里的順序如上圖。
  vector <Point > not_a_rect_shape;
                not_a_rect_shape.push_back(Point( 122, 0));
                not_a_rect_shape.push_back(Point( 814, 0));
                not_a_rect_shape.push_back(Point( 22, 540));
                not_a_rect_shape.push_back(Point( 910, 540));
並將這幾個點標注出來
         const Point * point = &not_a_rect_shape[ 0];
                 int n = ( int )not_a_rect_shape.size();
                Mat draw = src.clone();
                polylines(draw, &point, &n, 1true, Scalar( 0, 255, 0), 3, CV_AA);
                imwrite(  "draw.jpg", draw);
3、生成透視變換矩陣
   cv : :Point2f src_vertices[ 4];
                src_vertices[ 0] = not_a_rect_shape[ 0];
                src_vertices[ 1] = not_a_rect_shape[ 1];
                src_vertices[ 2] = not_a_rect_shape[ 2];
                src_vertices[ 3] = not_a_rect_shape[ 3];

                Point2f dst_vertices[ 4];
                dst_vertices[ 0] = Point( 0, 0);
                dst_vertices[ 1] = Point( 960, 0);
                dst_vertices[ 2] = Point( 0, 540);
                dst_vertices[ 3] = Point( 960, 540);
                Mat warpMatrix = getPerspectiveTransform(src_vertices, dst_vertices);
4、執行轉換
    cv : :Mat rotated;
                warpPerspective(src, rotated, warpMatrix, rotated.size(), INTER_LINEAR, BORDER_CONSTANT);
5、顯示並保存結果
        // Display the image
                cv : :namedWindow(  "Original Image");
                cv : :imshow(  "Original Image",src);
                cv : :namedWindow(  "warp perspective");
                cv : :imshow(  "warp perspective",rotated);
                imwrite(  "result.jpg",src);
結果:
原始圖片
標注四個邊界點
透視變換后的圖片
需要注意的是,這里變化后的圖像丟失了一些邊界細節,這在具體實現的時候是需要注意的。



2017年4月30日09:03:03 感謝 網友 CHEN Tian-hua 指出一處錯誤,已經將 最后的a12修改成a23

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM