zoukankan      html  css  js  c++  java
  • 仿射变换+透视变换

    原理

    由于用齐次坐标表示,三维几何变换的矩阵是一个4阶方阵,其形式如下:


    其中,产生按轴缩放、旋转、错切等变换。产生平移变换,产生投影变换,产生整体的缩放变换。

    在这个教程中你将学习到如何:

    1. 使用OpenCV函数 warpAffine 来实现一些简单的重映射.
    2. 使用OpenCV函数 getRotationMatrix2D 来获得一个 2 	imes 3 旋转矩阵

    原理

    什么是仿射变换?

    1. 一个任意的仿射变换都能表示为 乘以一个矩阵 (线性变换) 接着再 加上一个向量 (平移).

    2. 综上所述, 我们能够用仿射变换来表示:

      1. 旋转 (线性变换)
      2. 平移 (向量加)
      3. 缩放操作 (线性变换)

      你现在可以知道, 事实上, 仿射变换代表的是两幅图之间的 关系 .

    3. 我们通常使用 2 	imes 3 矩阵来表示仿射变换.

      A = egin{bmatrix}
     a_{00} & a_{01} \
     a_{10} & a_{11}
     end{bmatrix}_{2 	imes 2}
 B = egin{bmatrix}
     b_{00} \
     b_{10}
     end{bmatrix}_{2 	imes 1}

 M = egin{bmatrix}
     A & B
     end{bmatrix}
 =
egin{bmatrix}
     a_{00} & a_{01} & b_{00} \
     a_{10} & a_{11} & b_{10}
end{bmatrix}_{2 	imes 3}

      考虑到我们要使用矩阵 A 和 B 对二维向量 X = egin{bmatrix}x \ yend{bmatrix} 做变换, 所以也能表示为下列形式:

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

      T =  egin{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 (在图一中形成一个三角形) 与图二中三个点一一映射, 仍然形成三角形, 但形状已经大大改变. 如果我们能通过这样两组三点求出仿射变换 (你能选择自己喜欢的点), 接下来我们就能把仿射变换应用到图像中所有的点.

    //
    //#include<opencv2/opencv.hpp>
    //
    //using namespace cv;
    //
    //int main(int argc, char** argv)
    //{
    //    //Mat picture = imread("C:\Users\ranjiewen\Desktop\lena.bmp");
    //    //
    //    //imshow("测试程序", picture);
    //
    //    //flip();
    //    //threshold();
    //    //cvGetAffineTransform();
    //
    //    CvPoint2D32f srcTri[3], dstTri[3];
    //    CvMat* rot_mat = cvCreateMat(2, 3, CV_32FC1);
    //    CvMat* warp_mat = cvCreateMat(2, 3, CV_32FC1);
    //    IplImage* src = nullptr, *dst = nullptr;
    //
    //    if (argc == 1 && ((src = cvLoadImage("C:\Users\ranjiewen\Desktop\lena.bmp", 1)) != 0))  //==
    //    {
    //        dst = cvCloneImage(src);  //==
    //        dst->origin == src->origin;
    //        cvZero(dst);
    //
    //        srcTri[0].x = 0;
    //        srcTri[0].y = 0;
    //        srcTri[1].x = src->width - 1;
    //        srcTri[1].y = 0;
    //        srcTri[2].x = 0;
    //        srcTri[2].y = src->height - 1;
    //
    //        dstTri[0].x = src->width*0.0;
    //        dstTri[0].y = src->height*0.33;
    //        dstTri[1].x = src->width*0.85;
    //        dstTri[1].y = src->height*0.25;
    //        dstTri[2].x = src->width*0.15;
    //        dstTri[2].y = src->height*0.7;
    //
    //        cvGetAffineTransform(srcTri, dstTri, warp_mat);
    //        cvWarpAffine(src, dst, warp_mat);
    //        cvCopy(dst, src);
    //
    //        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);
    //
    //        cvNamedWindow("Affine_Transform", 1);   /*第二个参数,int 类型的flags ,窗口的标识,可以填如下的值:
    //                                                WINDOW_NORMAL设置了这个值,用户便可以改变窗口的大小(没有限制)
    //                                                INDOW_AUTOSIZE如果设置了这个值,窗口大小会自动调整以适应所显示的图像,并且不能手动改变窗口大小.
    //                                                WINDOW_OPENGL 如果设置了这个值的话,窗口创建的时候便会支持OpenGL*/
    //        cvSize(100, 100);
    //        cvShowImage("Affine_Transform", dst);
    //        cvWaitKey();
    //    }
    //
    //    cvReleaseImage(&dst);
    //    cvReleaseMat(&rot_mat);
    //    cvReleaseMat(&warp_mat);
    //    system("pause");
    //
    //    //waitKey(0);
    //    return 0;
    //}
    //
    //
    
    
    #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("C:\Users\ranjiewen\Desktop\lena.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;
    }

    两个版本都可以,实验结果:

    参考:http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/imgproc/imgtrans/warp_affine/warp_affine.html#warp-affine  即opencv的中文论坛上可以很好的帮助学习opencv,有很多例子程序

           OpenCV 教程

           http://blog.csdn.net/hitwengqi/article/details/6888783

  • 相关阅读:
    mybatis中的#和$的区别
    error: 40
    SenseTime Ace Coder Challenge 暨 商汤在线编程挑战赛* B. 我觉得海星
    AtCoder Regular Contest 093 D
    AtCoder Regular Contest 092 D
    2018 蓝桥杯省赛 B 组模拟赛(五) 结果填空:藏宝图
    2018/3/22 美团在线笔试 编程题
    2018/3/22美团在线笔试
    2018 蓝桥杯省赛 B 组模拟赛(一)青出于蓝胜于蓝
    心情小记
  • 原文地址:https://www.cnblogs.com/ranjiewen/p/5967464.html
Copyright © 2011-2022 走看看