• 【OpenCV】-仿射变换


    1、认识仿射变换

    仿射变换(Affine Map)又称仿射映射,是指在几何中,一个向量空间进行一次线性变换并接上一个平移,变换为另一个向量空间的过程。保持二维图形之间的相对位置保持不变,平行线依然是平行线,且直线上的点的位置顺序不变。

    一个任意的仿射变换都可以表示为乘以一个矩阵接着再加上一个向量的形式。三种常见的变换形式:

    • 旋转:ratation(线性变换)
    • 平移:translation(向量加)
    • 缩放:scale(线性变换)

    通常使用2 x 3的矩阵来表示仿射变换:

    在这里插入图片描述

    在这里插入图片描述

    2、仿射变换的求法

    说明:仿射变换表示的就是两幅图片之间的一种联系,关于这种联系的信息大致可以分为以下两种场景:

    • 已知X和T,而且已知它们是有联系的,接下来的跟着就是求出矩阵M。
    • 已知M和X,想要求得T。只要应用算式T=M*X即可。

    在这里插入图片描述

    如上,点1、2、3(在Image 1中形成一个三角形)与Image 2中的三个点是一一映射的关系,且它们仍然形成三角形,但形状已经和之前的不一样的,可以通过这样的两组三点求出仿射变换,然后把这种变换应用到图像中去。

    3、进行仿射变换:warpAffine()函数

    warpAffine()函数的作用依据下面的公式对图像做仿射变换:
    d s t ( x , y ) = s r c ( M 11 X + M 12 Y + M 13 , M 21 X + M 22 Y + M 23 ) dst(x,y)=src(M11X+M12Y+M13,M21X+M22Y+M23) dst(x,y)=src(M11X+M12Y+M13,M21X+M22Y+M23)

    void warpAffine(InputArray src,OutputArray dst,InputArray M,Size dsize,int flags=INTER_LINEAR,intborderMOde=BODER_CONSTANT,const Scalar& borderValue=Scalar())
    
    • 1
    • 第一个参数:输入图像

    • 第二个参数:输出图像,函数调用后的运算结果存在这里,需要和源图片有一样的尺寸和类型

    • 第三个参数:2 x 3的变换矩阵,求得的仿射变换

    • 第四个参数:表示输出图像的尺寸

    • 第五个参数:插值方法的标识符。默认值是线性插值法(INTER_LINEAR)

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oCWwUOWK-1659625193572)(F:\学习记录\opencv\截图\image-20220804143908462.png)]

    • 第六个参数:边界像素模式

    • 第七个参数:在恒定的边界情况下取值,默认值Scalar(),即0

    4、计算二维旋转变换矩阵:getRotationMatrix2D()函数

    说明:getRotationMatrix2D()函数用于计算二维旋转变换矩阵。变换会将旋转中心映射到它自身

    Mat getRotationMatrix2D(Point2f center,double angle,double scale)
    
    • 1
    • 第一个参数:表示源图像的旋转中心
    • 第二个参数:旋转角度。角度为正值表示向逆时针旋转(坐标原点是左上角)
    • 第三个参数:缩放系统

    5、示例程序:

    #include
    #include
    #include
    #include
    using namespace std;
    using namespace cv;
    #define WINDOW_NAME1 "【原始图窗口】"
    #define WINDOW_NAME2 "【经过Warp后的窗口】"
    #define WINDOW_NAME3 "【经过Warp和Rotate后的窗口】"
    int main()
    {
    	system("color 2F");
    	//参数准备
    	Point2f srcTriangle[3];
    	Point2f dstTriangle[3];
    
    	Mat rotMat(2, 3, CV_32FC1);
    	Mat warpMat(2, 3, CV_32FC1);
    	Mat srcImage, dstImage_warp, dstImage_warp_rotate;
    	//加载源图像
    	srcImage = imread("E:\\Pec\\lan.jpg",1);
    	//设置目标图像的大小和类型与源图像一致
    	dstImage_warp = Mat::zeros(srcImage.rows, srcImage.cols, srcImage.type());
    	//设置源图像和目标图像上的三组点以计算仿射变换
    	//srcTriangle[0] = Point2f(0, 0); //Point2f表示Point类的两个数据x,y为float类型;vector 表示存放四维int
    	//srcTriangle[1] = Point2f(static_cast(srcImage.cols - 1), 0);
    	//srcTriangle[2] = Point2f(0, static_cast(srcImage.rows - 1));
    	//dstTriangle[0] = Point2f(static_cast(srcImage.cols*0.0), static_cast(srcImage.rows*0.33));
    	//dstTriangle[1] = Point2f(static_cast(srcImage.cols*0.65), static_cast(srcImage.rows*0.35));
    	//dstTriangle[2] = Point2f(static_cast(srcImage.cols*0.15), static_cast(srcImage.rows*0.6));
    	//获取变换矩阵,指定三个点
    	srcTriangle[0] = Point2f(50, 50); 
    	srcTriangle[1] = Point2f(200, 50);
    	srcTriangle[2] = Point2f(50, 200);
    	dstTriangle[0] = Point2f(100, 100);
    	dstTriangle[1] = Point2f(200, 50);
    	dstTriangle[2] = Point2f(100, 250);
    	//求仿射变换,得到一个2x3的矩阵
    	warpMat = getAffineTransform(srcTriangle, dstTriangle);
    	//对源图像应用刚刚的求得的仿射变换
    	warpAffine(srcImage, dstImage_warp, warpMat, dstImage_warp.size());
    
    	//对图像进行缩放后再旋转
    	//计算图像中点顺时针旋转50°缩放因子为0.6的旋转矩阵
    	Point center = Point(dstImage_warp.cols / 2, dstImage_warp.rows / 2);
    	double angle = -30.0;
    	double scale = 0.8;
    	//通过上面的旋转细节信息求出旋转矩阵
    	rotMat = getRotationMatrix2D(center, angle, scale);
    	//旋转已经缩放后的图像
    	warpAffine(dstImage_warp, dstImage_warp_rotate, rotMat, dstImage_warp.size());
    	imshow(WINDOW_NAME1, srcImage);
    	imshow(WINDOW_NAME2, dstImage_warp);
    	imshow(WINDOW_NAME3, dstImage_warp_rotate);
    	waitKey(0);
    	return 0;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58

    在这里插入图片描述

  • 相关阅读:
    亚马逊云科技顾凡解读云计算助力初创快速抢滩生成式AI新风口
    Flutter 最佳实践 - 04
    2023年最新版Apollo保姆级使用手册(超级详尽版本)
    小程序真题合集
    达索智能制造解决方案,敏捷电芯制造如何赋能企业竞争力 | 百世慧®
    Java 8 中需要知道的4个函数式接口-Function、Consumer、Supplier、Predicate
    一款超好用的开源内存剖析器,今天教你怎么用!
    SpringBoot 自动装配原理
    matlab分岔图绘制
    房屋信贷违约风险竞争(kaggle)系列4-基准模型
  • 原文地址:https://blog.csdn.net/qq_44859533/article/details/126168178