zoukankan      html  css  js  c++  java
  • OpenCV 之 图像几何变换

      二维平面中,图像的几何变换有等距、相似、仿射、投影等,如下所示:

       

    1  图象几何变换

    1.1  等距变换

        等距变换 (Isometric Transformation),是一种二维的刚体变换,可理解为旋转和平移的组合

       $quad egin{bmatrix} x^{prime} \ y^{prime} \ 1 end{bmatrix} = egin{bmatrix} cos heta & -sin heta & t_x \ sin heta & cos heta & t_y \ 0&0&1 end{bmatrix} egin{bmatrix} x \ y \ 1end{bmatrix}  =egin{bmatrix} R_{2 imes 2} & T_{2 imes 1} \ 0_{1 imes 2} & 1_{1 imes 1} end{bmatrix} egin{bmatrix} x \ y \1 end{bmatrix}$

        其中, $R=egin{bmatrix} cos heta &-sin heta \ sin heta & cos heta end{bmatrix}$ 为旋转矩阵, $T=egin{bmatrix}t_x \ t_y end{bmatrix}$ 为平移矩阵

        想象一个无限大的平面上,放一张极薄的图像照片,让它只能在平面内做旋转和平移运动,则这样的运动就是等距变换

        

    1.2  相似变换

      相似变换 (Similarity Transformation),是一个等距变换和各向均匀缩放的组合

       $quad egin{bmatrix} x' \ y' \ 1 end{bmatrix} = egin{bmatrix} s cos heta & -ssin heta & t_x \ s sin heta & s cos heta & t_y \ 0&0&1 end{bmatrix} egin{bmatrix} x \ y \ 1end{bmatrix} = egin{bmatrix} sR_{2 imes 2} & T_{2 imes 1} \ 0_{1 imes 2} & 1_{1 imes 1} end{bmatrix} egin{bmatrix} x \ y \1 end{bmatrix}$,其中 $s$ 为缩放系数

       想象无限大平面内的一张图片,在旋转和平移的过程中,其大小也会均匀缩放(各个方向),则这样的变换就是相似变换

       -- 配图

    1.3  仿射变换

    1.3.1  定义

        仿射变换(Affine Transformation),是一个非奇异线性变变换 (矩阵乘法) 和 平移变换 (向量加法) 的组合

        矩阵表达式为 $quad egin{bmatrix} x' \ y' \ 1 end{bmatrix} = egin{bmatrix} a_{11} & a_{12} & t_x \ a_{21} & a_{22} & t_y \ 0 & 0 & 1 end{bmatrix} egin{bmatrix} x \ y \ 1 end{bmatrix} =egin{bmatrix} A_{2 imes 2} & T_{2 imes 1} \ 0_{1 imes 2} & 1_{1 imes 1} end{bmatrix} egin{bmatrix} x \ y \1 end{bmatrix}$

        其中,当 $A = egin{bmatrix} a_{11} & a_{12} \ a_{21} & a_{22} end{bmatrix}$ 是非奇异时,称 $A$ 为仿射矩阵

    1.3.2  分解

        仿射矩阵 $A$ 可分解为:旋转和各向 (正交) 非均匀缩放

        $quad A = R( heta) R(-phi) D R(phi)$,其中 $D = egin{bmatrix} lambda_1 & 0 \ 0 & lambda_2 end{bmatrix}$是一个对角矩阵

        首先,旋转角度 $phi$;然后在 $x$ 和 $y$ 方向上 (其中 $xperp y$) 分别缩放 $lambda_1$ 和 $lambda_2$;再旋转角度 $-phi$,也即回转 $phi$;最后旋转角度 $ heta$

        本质上,平面中的仿射变换,就是奇异值分解的过程:$A=UDV^T$

         

        想象无限大光滑平面内的一张图片,在旋转和平移的过程中,其大小在正交方向上非均匀缩放,则这样的变换就是仿射变换

    1.3.3  不变量

        仿射变换的过程中,有三个重要的不变量,分别是:平行线,平行线段长度比,面积比

    2  OpenCV 函数    

    2.1  相似变换的矩阵

        对于相似变换,有 4 个未知数 ($s, heta, t_x, t_y$),对应 OpenCV 中的 getRotationMatrix2D() 函数    

      Mat getRotationMatrix2D (
          Point2f     center,  // 原图像中的旋转中心点
          double      angle,   // 旋转角度(正值代表逆时针旋转)
          double      scale    // 均匀缩放系数
      )

        该函数可得到如下矩阵:

        $egin{bmatrix} alpha & eta & (1- alpha ) cdot exttt{center.x} - eta cdot exttt{center.y} \ - eta & alpha & eta cdot exttt{center.x} + (1- alpha ) cdot exttt{center.y} end{bmatrix}$

        其中, $alpha=scale cdot cos angle$

                    $eta=scale cdot sin angle$

    2.2  仿射变换的矩阵

        仿射变换有 6 个未知数 ($phi, heta, lambda_1, lambda_2, t_x, t_y$),需列 6 组方程,而一组对应特征点 $(x,y)$ -> $(x′,y′)$ 可构造 2 个方程,因此,求解 6 个未知数,需要 3 组对应特征点

            

        OpenCV 中 getAffineTransform() 可求解 2x3 矩阵 $egin{bmatrix} a_{11} & a_{12} & t_{x} \ a_{21} & a_{22} & t_y end{bmatrix}$     

      Mat getAffineTransform (
          const Point2f    src[],  // 原图像的三角顶点坐标
          const Point2f    dst[]   // 目标图像的三角顶点坐标
      )   

        其代码实现比较简单,先构建方程组,再利用 solve() 求解 $Ax=b$   

    Mat getAffineTransform(const Point2f src[], const Point2f dst[])
    {
        Mat M(2, 3, CV_64F), X(6, 1, CV_64F, M.ptr());
        double a[6 * 6], b[6];
        Mat A(6, 6, CV_64F, a), B(6, 1, CV_64F, b);
    
        for (int i = 0; i < 3; i++)
        {
            int j = i * 12;
            int k = i * 12 + 6;
            a[j] = a[k + 3] = src[i].x;
            a[j + 1] = a[k + 4] = src[i].y;
            a[j + 2] = a[k + 5] = 1;
            a[j + 3] = a[j + 4] = a[j + 5] = 0;
            a[k] = a[k + 1] = a[k + 2] = 0;
            b[i * 2] = dst[i].x;
            b[i * 2 + 1] = dst[i].y;
        }
    
        solve(A, B, X);
        return M;
    }

    2.3  仿射变换的图象 

         已知仿射变换的 $A_{2 imes 2}$ 和 $T_{2 imes 1}$ ,将任意图像代入 warpAffine() ,便可得到仿射变换后的目标图像        

    void warpAffine(
        InputArray      src,    // 输入图象
        OutputArray     dst,    // 输出图像(大小为 dsize,类型同 src)
        InputArray       M,     // 2x3 矩阵
        Size            dsize,  // 输出图像的大小
        int  flags = INTER_LINEAR,
        int  borderMode = BORDER_CONSTANT,
        const Scalar& borderValue = Scalar()
    )

        

    3  代码示例

        首先构造3组三角顶点坐标,代入 getAffineTransform() 得到仿射变换的矩阵;再用 getRotationMatrix2D() 构造相似变换的矩阵;然后,warpAffine() 求解经过相似变换和仿射变换的图像;最后,显示对比变换后的目标图像

    #include "opencv2/core.hpp"
    #include "opencv2/imgproc.hpp"
    #include "opencv2/imgcodecs.hpp"
    #include "opencv2/highgui.hpp"
    
    using namespace cv;
    
    int main()
    {
        // 1) read image
        Mat src = imread("horse.jpg");
        
        // 2) triangle vertices
        Point2f srcTri[3];
        srcTri[0] = Point2f(0.f, 0.f);
        srcTri[1] = Point2f(src.cols - 1.f, 0.f);
        srcTri[2] = Point2f(0.f, src.rows - 1.f);
    
        Point2f dstTri[3];
        dstTri[0] = Point2f(0.f, src.rows * 0.33f);
        dstTri[1] = Point2f(src.cols * 0.85f, src.rows * 0.25f);
        dstTri[2] = Point2f(src.cols * 0.15f, src.rows * 0.7f);
    
        // 3.1) getAffineTransform
        Mat warp_mat1 = getAffineTransform(srcTri, dstTri);

    // 3.2) getRotationMatrix2D Mat warp_mat2 = getRotationMatrix2D(Point2f(0.5*src.cols, 0.5*src.rows), 45, 0.5); // 4) warpAffine image Mat dst1,dst2; warpAffine(src, dst1, warp_mat1, Size(src.cols, src.rows)); warpAffine(src, dst2, warp_mat2, Size(src.cols, src.rows)); // 5) show image imshow("image", src); imshow("warp affine 1", dst1); imshow("warp affine 2", dst2); waitKey(0); }

          检测结果对比如下:

                   

    参考资料

        《Computer Vision: Algorithms and Applications》 Chapter 2 Image Formation

        《Multiple View Geometry in Computer Vision》   2.4  A hierarchy of transformations

        OpenCV Tutorials / Image Processing (imgproc module) / Affine Transformations

        OpenCV-Python Tutorials / Image Processing in OpenCV / Geometric Transformations of Images 

        

    原文链接: http://www.cnblogs.com/xinxue/

    专注于机器视觉、OpenCV、C++ 编程

  • 相关阅读:
    poj 3528 (三维几何求凸包+凸包表面积)
    dijkstra模板(好像是斐波那契额堆优化,但我为什么看起来像优先队列优化,和spfa一样)
    最大空凸包模板
    ICPC 2017–2018, NEERC, Northern Subregional Contest St Petersburg, November 4, 2017 I题
    hdu 5248 序列变换
    hdu 2063(二分图模板测试)
    组合数
    85. Maximal Rectangle 由1拼出的最大矩形
    750. Number Of Corner Rectangles四周是点的矩形个数
    801. Minimum Swaps To Make Sequences Increasing 为使两个数组严格递增,所需要的最小交换次数
  • 原文地址:https://www.cnblogs.com/xinxue/p/14576901.html
Copyright © 2011-2022 走看看