學習OpenCv反射ch6_ex6_2

1. 仿射變換

1) 用途

旋轉 (線性變換),平移(向量加).縮放(線性變換),錯切,反轉

2) 方法

仿射變換是一種二維座標到二維座標之間的線性變換,它保持了二維圖形的“平直性”(直線經過變換之後依然是直線)和“平行性”(二維圖形之間的相對位置關係保持不變,平行線依然是平行線,且直線上點的位置順序不變)。任意的仿射變換都能表示爲乘以一個矩陣(線性變換),再加上一個向量 (平移) 的形式.

原理

由於用齊次座標表示,三維幾何變換的矩陣是一個4階方陣,其形式如下:

其中,產生按軸縮放、旋轉、錯切等變換。產生平移變換,產生投影變換,產生整體的縮放變換。

什麼是仿射變換?

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

  2. 綜上所述, 我們能夠用仿射變換來表示:

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

    你現在可以知道, 事實上, 仿射變換代表的是兩幅圖之間的 關係 .

  3. 我們通常使用 2 \times 3 矩陣來表示仿射變換.

    A = \begin{bmatrix}      a_{00} & a_{01} \\      a_{10} & a_{11}      \end{bmatrix}_{2 \times 2}  B = \begin{bmatrix}      b_{00} \\      b_{10}      \end{bmatrix}_{2 \times 1}   M = \begin{bmatrix}      A & B      \end{bmatrix}  = \begin{bmatrix}      a_{00} & a_{01} & b_{00} \\      a_{10} & a_{11} & b_{10} \end{bmatrix}_{2 \times 3}

    考慮到我們要使用矩陣 A 和 B 對二維向量 X = \begin{bmatrix}x \\ y\end{bmatrix} 做變換, 所以也能表示爲下列形式:

    T = A \cdot \begin{bmatrix}x \\ y\end{bmatrix} + B or T = M \cdot  [x, y, 1]^{T}

    T =  \begin{bmatrix}     a_{00}x + a_{01}y + b_{00} \\     a_{10}x + a_{11}y + b_{10}     \end{bmatrix}

 怎樣才能求得一個仿射變換?

  1. 好問題. 我們在上文有提到過仿射變換基本表示的就是兩幅圖片之間的 聯繫 . 關於這種聯繫的信息大致可從以下兩種場景獲得:

    1. 我們已知 X 和 T 而且我們知道他們是有聯繫的. 接下來我們的工作就是求出矩陣 M
    2. 我們已知 M and X. 要想求得 T. 我們只要應用算式 T = M \cdot X 即可. 對於這種聯繫的信息可以用矩陣 M 清晰的表達 (即給出明確的2×3矩陣) 或者也可以用兩幅圖片點之間幾何關係來表達.
  2. 讓我們形象地說明一下. 因爲矩陣 M 聯繫着兩幅圖片, 我們以其表示兩圖中各三點直接的聯繫爲例. 見下圖:

    Theory of Warp Affine
  3. 點1, 2 和 3 (在圖一中形成一個三角形) 與圖二中三個點一一映射, 仍然形成三角形, 但形狀已經大大改變. 如果我們能通過這樣兩組三點求出仿射變換 (你能選擇自己喜歡的點), 接下來我們就能把仿射變換應用到圖像中所有的點.
     

    #if 1
    
    #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("f.bmp", 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;
    }
    #endif
    
    // warp_affine <image>
    #include <cv.h>
    #include <highgui.h>
    //#define affine 
    #ifdef affine
    int main(int argc, char** argv)
    {
       CvPoint2D32f srcTri[3], dstTri[3];
       CvMat* rot_mat = cvCreateMat(2,3,CV_32FC1);
       CvMat* warp_mat = cvCreateMat(2,3,CV_32FC1);
       IplImage *src, *dst;
        if( argc == 2 && ((src=cvLoadImage(argv[1],1)) != 0 ))
        {
       dst = cvCloneImage(src);
       dst->origin = src->origin;
       cvZero(dst);//將圖像中的每個像素都置爲0,那麼顯示的frame自然就是全黑了
    
       //COMPUTE WARP MATRIX
       srcTri[0].x = 0;          //src Top left
       srcTri[0].y = 0;
       srcTri[1].x = src->width - 1;    //src Top right
       srcTri[1].y = 0;
       srcTri[2].x = 0;          //src Bottom left
       srcTri[2].y = src->height - 1;
       //- - - - - - - - - - - - - - -//
       dstTri[0].x = src->width*0.0;    //dst Top left
       dstTri[0].y = src->height*0.33;
       dstTri[1].x = src->width*0.85; //dst Top right
       dstTri[1].y = src->height*0.25;
       dstTri[2].x = src->width*0.15; //dst Bottom left
       dstTri[2].y = src->height*0.7;
       cvGetAffineTransform(srcTri,dstTri,warp_mat);// 求得仿射變換warp_mat
       cvWarpAffine(src,dst,warp_mat);// 對源圖像應用上面求得的仿射變換
       cvCopy(dst,src);
       /** 對圖像扭曲後再旋轉 */
    
       //COMPUTE ROTATION MATRIX
       /// 計算繞圖像中點順時針旋轉50度縮放因子爲0.6的旋轉矩陣
       CvPoint2D32f center = cvPoint2D32f(src->width/2,
                                             src->height/2);
       double angle = -50.0;
       double scale = 0.6;
       /// 通過上面的旋轉細節信息求得旋轉矩陣
       cv2DRotationMatrix(center,angle,scale,rot_mat);
       /// 旋轉已扭曲圖像
       cvWarpAffine(src,dst,rot_mat);
    
       //DO THE TRANSFORM:
       cvNamedWindow( "Affine_Transform", 1 );
          cvShowImage( "Affine_Transform", dst );
          cvWaitKey();
        }
       cvReleaseImage(&dst);
       cvReleaseMat(&rot_mat);
       cvReleaseMat(&warp_mat);
        return 0;
    }
    #endif

    效果:

                       

                                  

https://www.cnblogs.com/ranjiewen/p/5967464.html 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章