美文网首页图像处理互联网@时事传播想法
【图像处理】OpenCV系列十六 --- 仿射变换warpAff

【图像处理】OpenCV系列十六 --- 仿射变换warpAff

作者: 307656af5a04 | 来源:发表于2019-04-29 19:32 被阅读57次

    上一节我们学习了如何对一幅图像进行放大与缩小(resize函数)以及对插值算的原理进行了分析,相信大家对图像如何进行放大与缩小已经有了清晰的理解,那么我们这节学习OpenCV中比较重要的内容,即仿射变换(warpAffine),仿射变换可以实现对稍微倾斜的图片进行矫正哦!!那么接下来我们就正式进入仿射变换的学习吧!

    一、原理

    仿射变换的功能是从二维坐标到二维坐标之间的线性变换,且保持二维图形的“平直性”和“平行性”。仿射变换可以通过一系列的原子变换的复合来实现,包括平移,缩放,翻转,旋转和剪切。

    这类变换可以用一个3*3的矩阵M来表示,其最后一行为(0,0,1)。该变换矩阵将原坐标为(x,y)变换为新坐标(x',y')

    仿射变换

    典型的仿射变换
    1、平移
    将每一点移到到(x+t , y+t),变换矩阵为

    平移

    2、缩放变换
    将每一点的横坐标放大或缩小s_x倍,纵坐标放大(缩小)到s_y倍,变换矩阵为

    缩放变换

    3、旋转变换原点
    目标图形围绕原点顺时针旋转Θ 弧度,变换矩阵为

    旋转变换原点

    4、旋转变换
    目标图形以(x , y )为轴心顺时针旋转θ弧度,变换矩阵为

    旋转变换

    二、OpenCV中warpAffine()相关函数详解

    (一)warpAffine()函数
    1、函数原型

    void warpAffine(InputArray src, 
        OutputArray dst,
        InputArray M, 
        Size dsize,
        int flags = INTER_LINEAR,
        int borderMode = BORDER_CONSTANT,
        const Scalar& borderValue = Scalar());
    

    2、函数功能
    对图像进行仿射变换,当函数的参数flags设置为 WARP_INVERSE_MAP时,函数使用下面的矩阵进行仿射变换:

    仿射变换

    否则,函数将首先使用逆仿射变换的转置,然后用上面的公式代替M,并且该函数不支持就地操作。

    3、参数详解

    • 第一个参数,InputArray src,原图像;

    • 第二个参数,OutputArray dst,目标图像,并且该图像与原图像的尺寸和类型都是一样的;

    • 第三个参数,InputArray M,2 x 3的变换矩阵;

    • 第四个参数,Size dsize,目标图像的大小;

    • 第五个参数,int flags = INTER_LINEAR,插值算法的标识符,默认为线性插值(INTER_LINEAR),如果插值算法为WARP_INVERSE_MAP,则函数使用下面的上面的公式[放射变换]进行图像转换;

    • 第六个参数,int borderMode = BORDER_CONSTANT,边界像素的模式,默认值为BORDER_CONSTANT;

    • 第七个参数,const Scalar& borderValue = Scalar(),边界取值,默认值为Scalar()。

    4、实例

    #include <iostream>
    #include <opencv2/core.hpp>
    #include <opencv2/highgui.hpp>
    #include <opencv2/imgproc.hpp>
    
    using namespace std;
    using namespace cv;
    
    //全局变量
    String src_windowName = "原图像";
    String warp_windowName = "仿射变换";
    String warp_rotate_windowName = "仿射旋转变换";
    String rotate_windowName = "图像旋转";
    
    int main()
    {
        Point2f srcTri[3];
        Point2f dstTri[3];
    
        Mat rot_mat(2, 3, CV_32FC1);
        Mat warp_mat(2, 3, CV_32FC1);
        Mat srcImage, warp_dstImage, 
            warp_rotate_dstImage, rotate_dstImage;
    
        //加载图像
        srcImage = imread("lena.png");
    
        //判断文件是否加载成功
        if (srcImage.empty())
        {
            cout << "图像加载失败!" << endl;
            return -1;
        }
        else
            cout << "图像加载成功!" << endl << endl;
    
        //创建仿射变换目标图像与原图像尺寸类型相同
        warp_dstImage = Mat::zeros(srcImage.rows, 
            srcImage.cols, srcImage.type());
    
        //设置三个点来计算仿射变换
        srcTri[0] = Point2f(0, 0);
    
        srcTri[1] = Point2f(srcImage.cols - 1, 0);
    
        srcTri[2] = Point2f(0, srcImage.rows - 1);
    
        dstTri[0] = Point2f(srcImage.cols*0.0, 
            srcImage.rows*0.33);
    
        dstTri[1] = Point2f(srcImage.cols*0.85, 
            srcImage.rows*0.25);
    
        dstTri[2] = Point2f(srcImage.cols*0.15, 
            srcImage.rows*0.7);
    
        //计算仿射变换矩阵
        warp_mat = getAffineTransform(srcTri, dstTri);
    
        //对加载图形进行仿射变换操作
        warpAffine(srcImage, warp_dstImage, 
            warp_mat, warp_dstImage.size());
    
        //计算图像中点顺时针旋转90度,缩放因子为0.6的旋转矩阵
        Point center = Point(warp_dstImage.cols / 2, 
            warp_dstImage.rows / 2);
    
        double angle = -90.0;
        double scale = 0.6;
    
        //计算旋转矩阵
        rot_mat = getRotationMatrix2D(center, angle, scale);
    
        //旋转已扭曲图像
        warpAffine(warp_dstImage, warp_rotate_dstImage, 
            rot_mat, warp_dstImage.size());
    
        //将原图像旋转
        warpAffine(srcImage, rotate_dstImage, 
            rot_mat, srcImage.size());
    
        //显示变换结果
        namedWindow(src_windowName, WINDOW_AUTOSIZE);
    
        imshow(src_windowName, srcImage);
    
        namedWindow(warp_windowName, WINDOW_AUTOSIZE);
    
        imshow(warp_windowName, warp_dstImage);
    
        namedWindow(warp_rotate_windowName, WINDOW_AUTOSIZE);
    
        imshow(warp_rotate_windowName, warp_rotate_dstImage);
    
        namedWindow(rotate_windowName, WINDOW_AUTOSIZE);
    
        imshow(rotate_windowName, rotate_dstImage);
    
        waitKey(0);
    
        return 0;
    }
    

    实验结果

    原图
    仿射变换、仿射旋转变换、图像旋转90度

    (二)getAffineTransform()函数
    1、函数原型

    Mat getAffineTransform(const Point2f src[], 
        const Point2f dst[]);
    

    2、函数功能
    从三对相对应的点计算图像的仿射变换。

    3、参数详解

    • 第一个参数,const Point2f src[],坐标系中,原图像中三角形的坐标;

    • 第二个参数,const Point2f dst[],坐标系中,目标图像中相应的(相对于原图像)三角型的坐标;

    • 返回值为Mat类型的图像。

    (三)getRotationMatrix2D()函数
    1、函数原型

    Mat getRotationMatrix2D(Point2f center,
        double angle, double scale);
    

    2、函数功能
    计算二维图像旋转的放射变换。

    3、参数详解

    • 第一个参数,Point2f center,原图像的旋转中心坐标;

    • 第二个参数,double angle,旋转的角度,假定坐标原点为左上角,角度为正值的话,按逆时针的方向进行旋转,角度为负值的话,按顺时针的角度进行旋转;

    • 第三个参数,double scale,图像的缩放因子;

    • 返回值为Mat类型的图像。

    三、综合实例

    使用findTransformECC()函数实现图像对齐ECC算法

    image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png

    实验结果

    实验结果

    好了,今天的学习到这里就结束了,希望大家可以认真学习学习每一节知识,加油,相信大家可以的!喜欢的朋友也可以给我点个赞哦!!

    相关文章

      网友评论

        本文标题:【图像处理】OpenCV系列十六 --- 仿射变换warpAff

        本文链接:https://www.haomeiwen.com/subject/ybhenqtx.html