OpenCV實現仿射變換

什麼是仿射變換?

  1. 一個任意的仿射變換都能表示爲 乘以一個矩陣 (線性變換) 接着再 加上一個向量 (平移).html

  2. 綜上所述, 咱們可以用仿射變換來表示:ios

    1. 旋轉 (線性變換)
    2. 平移 (向量加)
    3. 縮放操做 (線性變換)

    你如今能夠知道, 事實上, 仿射變換表明的是兩幅圖之間的 關係 .數組

 

#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
#include <stdio.h>

using namespace cv;
using namespace std;

/// 全局變量
char* source_window = "Source image";
char* warp_window = "Warp";
char* warp_rotate_window = "Warp + Rotate";

/** @function main */
 int main( int argc, char** argv )
 {
   Point2f srcTri[3];
   Point2f dstTri[3];

   Mat rot_mat( 2, 3, CV_32FC1 );
   Mat warp_mat( 2, 3, CV_32FC1 );
   Mat src, warp_dst, warp_rotate_dst;


   /// 加載源圖像
   /// src = imread( argv[1], 1 );
	src = imread("./001.jpg", 1 );

   /// 設置目標圖像的大小和類型與源圖像一致
   warp_dst = Mat::zeros( src.rows, src.cols, src.type() );

   /// 設置源圖像和目標圖像上的三組點以計算仿射變換
   srcTri[0] = Point2f( 0,0 );
   srcTri[1] = Point2f( src.cols - 1, 0 );
   srcTri[2] = Point2f( 0, src.rows - 1 );

   dstTri[0] = Point2f( src.cols*0.0, src.rows*0.33 );
   dstTri[1] = Point2f( src.cols*0.85, src.rows*0.25 );
   dstTri[2] = Point2f( src.cols*0.15, src.rows*0.7 );

   /// 求得仿射變換
   warp_mat = getAffineTransform( srcTri, dstTri );

   /// 對源圖像應用上面求得的仿射變換
   warpAffine( src, warp_dst, warp_mat, warp_dst.size() );

   /** 對圖像扭曲後再旋轉 */

   /// 計算繞圖像中點順時針旋轉50度縮放因子爲0.6的旋轉矩陣
   Point center = Point( warp_dst.cols/2, warp_dst.rows/2 );
   double angle = -50.0;
   double scale = 0.6;

   /// 經過上面的旋轉細節信息求得旋轉矩陣
   rot_mat = getRotationMatrix2D( center, angle, scale );

   /// 旋轉已扭曲圖像
   warpAffine( warp_dst, warp_rotate_dst, rot_mat, warp_dst.size() );

   /// 顯示結果
   namedWindow( source_window, CV_WINDOW_AUTOSIZE );
   imshow( source_window, src );

   namedWindow( warp_window, CV_WINDOW_AUTOSIZE );
   imshow( warp_window, warp_dst );

   namedWindow( warp_rotate_window, CV_WINDOW_AUTOSIZE );
   imshow( warp_rotate_window, warp_rotate_dst );

   /// 等待用戶按任意按鍵退出程序
   waitKey(0);

   return 0;
  }

說明函數

  1. 定義一些須要用到的變量, 好比須要用來儲存中間和目標圖像的Mat和兩個須要用來定義仿射變換的二維點數組.ui

    Point2f srcTri[3];
    Point2f dstTri[3];
    
    Mat rot_mat( 2, 3, CV_32FC1 );
    Mat warp_mat( 2, 3, CV_32FC1 );
    Mat src, warp_dst, warp_rotate_dst;
  2. 加載源圖像:spa

    src = imread( argv[1], 1 );
  3. 以與源圖像一樣的類型和大小來對目標圖像初始化:code

    warp_dst = Mat::zeros( src.rows, src.cols, src.type() );
  4. 仿射變換: 正如上文所說, 咱們須要源圖像和目標圖像上分別一一映射的三個點來定義仿射變換:orm

    srcTri[0] = Point2f( 0,0 );
    srcTri[1] = Point2f( src.cols - 1, 0 );
    srcTri[2] = Point2f( 0, src.rows - 1 );
    
    dstTri[0] = Point2f( src.cols*0.0, src.rows*0.33 );
    dstTri[1] = Point2f( src.cols*0.85, src.rows*0.25 );
    dstTri[2] = Point2f( src.cols*0.15, src.rows*0.7 );

    你可能想把這些點繪出來以得到對變換的更直觀感覺. 他們的位置大概就是在上面圖例中的點的位置 (原理部分). 你會注意到由三點定義的三角形的大小和方向改變了.htm

  5. 經過這兩組點, 咱們可以使用OpenCV函數 getAffineTransform 來求出仿射變換:get

    warp_mat = getAffineTransform( srcTri, dstTri );

    咱們得到了用以描述仿射變換的 2X3 矩陣 (在這裏是 warp_mat)

  6. 將剛剛求得的仿射變換應用到源圖像

    warpAffine( src, warp_dst, warp_mat, warp_dst.size() );

    函數有如下參數:

    • src: 輸入源圖像
    • warp_dst: 輸出圖像
    • warp_mat: 仿射變換矩陣
    • warp_dst.size(): 輸出圖像的尺寸

    這樣咱們就得到了變換後的圖像! 咱們將會把它顯示出來. 在此以前, 咱們還想要旋轉它...

  7. 旋轉: 想要旋轉一幅圖像, 你須要兩個參數:

    1. 旋轉圖像所要圍繞的中心
    2. 旋轉的角度. 在OpenCV中正角度是逆時針的
    3. 可選擇: 縮放因子

    咱們經過下面的代碼來定義這些參數:

    Point center = Point( warp_dst.cols/2, warp_dst.rows/2 );
    double angle = -50.0;
    double scale = 0.6;
  8. 咱們利用OpenCV函數 getRotationMatrix2D 來得到旋轉矩陣, 這個函數返回一個 2X3  矩陣 (這裏是 rot_mat)

    rot_mat = getRotationMatrix2D( center, angle, scale );
  9. 如今把旋轉應用到仿射變換的輸出.

    warpAffine( warp_dst, warp_rotate_dst, rot_mat, warp_dst.size() );
  10. 最後咱們把仿射變換和旋轉的結果繪製在窗體中,源圖像也繪製出來以做參照:

    namedWindow( source_window, CV_WINDOW_AUTOSIZE );
    imshow( source_window, src );
    
    namedWindow( warp_window, CV_WINDOW_AUTOSIZE );
    imshow( warp_window, warp_dst );
    
    namedWindow( warp_rotate_window, CV_WINDOW_AUTOSIZE );
    imshow( warp_rotate_window, warp_rotate_dst );
  11. 等待用戶退出程序

    waitKey(0);
相關文章
相關標籤/搜索