OpenCV实现仿射变换

什么是仿射变换?

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

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

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

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

1#include <opencv2/highgui/highgui.hpp> 2#include <opencv2/imgproc/imgproc.hpp> 3#include <iostream> 4#include <stdio.h> 5 6using namespace cv; 7using namespace std; 8 9/// 全局变量 10char* source_window = "Source image"; 11char* warp_window = "Warp"; 12char* warp_rotate_window = "Warp + Rotate"; 13 14/** @function main */ 15 int main( int argc, char** argv ) 16 { 17 Point2f srcTri[3]; 18 Point2f dstTri[3]; 19 20 Mat rot_mat( 2, 3, CV_32FC1 ); 21 Mat warp_mat( 2, 3, CV_32FC1 ); 22 Mat src, warp_dst, warp_rotate_dst; 23 24 25 /// 加载源图像 26 /// src = imread( argv[1], 1 ); 27 src = imread("./001.jpg", 1 ); 28 29 /// 设置目标图像的大小和类型与源图像一致 30 warp_dst = Mat::zeros( src.rows, src.cols, src.type() ); 31 32 /// 设置源图像和目标图像上的三组点以计算仿射变换 33 srcTri[0] = Point2f( 0,0 ); 34 srcTri[1] = Point2f( src.cols - 1, 0 ); 35 srcTri[2] = Point2f( 0, src.rows - 1 ); 36 37 dstTri[0] = Point2f( src.cols*0.0, src.rows*0.33 ); 38 dstTri[1] = Point2f( src.cols*0.85, src.rows*0.25 ); 39 dstTri[2] = Point2f( src.cols*0.15, src.rows*0.7 ); 40 41 /// 求得仿射变换 42 warp_mat = getAffineTransform( srcTri, dstTri ); 43 44 /// 对源图像应用上面求得的仿射变换 45 warpAffine( src, warp_dst, warp_mat, warp_dst.size() ); 46 47 /** 对图像扭曲后再旋转 */ 48 49 /// 计算绕图像中点顺时针旋转50度缩放因子为0.6的旋转矩阵 50 Point center = Point( warp_dst.cols/2, warp_dst.rows/2 ); 51 double angle = -50.0; 52 double scale = 0.6; 53 54 /// 通过上面的旋转细节信息求得旋转矩阵 55 rot_mat = getRotationMatrix2D( center, angle, scale ); 56 57 /// 旋转已扭曲图像 58 warpAffine( warp_dst, warp_rotate_dst, rot_mat, warp_dst.size() ); 59 60 /// 显示结果 61 namedWindow( source_window, CV_WINDOW_AUTOSIZE ); 62 imshow( source_window, src ); 63 64 namedWindow( warp_window, CV_WINDOW_AUTOSIZE ); 65 imshow( warp_window, warp_dst ); 66 67 namedWindow( warp_rotate_window, CV_WINDOW_AUTOSIZE ); 68 imshow( warp_rotate_window, warp_rotate_dst ); 69 70 /// 等待用户按任意按键退出程序 71 waitKey(0); 72 73 return 0; 74 }

说明

  1. 定义一些需要用到的变量, 比如需要用来储存中间和目标图像的Mat和两个需要用来定义仿射变换的二维点数组.

    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;

  2. 加载源图像:

    src = imread( argv[1], 1 );

  3. 以与源图像同样的类型和大小来对目标图像初始化:

    warp_dst = Mat::zeros( src.rows, src.cols, src.type() );

  4. 仿射变换: 正如上文所说, 我们需要源图像和目标图像上分别一一映射的三个点来定义仿射变换:

    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 );

    你可能想把这些点绘出来以获得对变换的更直观感受. 他们的位置大概就是在上面图例中的点的位置 (原理部分). 你会注意到由三点定义的三角形的大小和方向改变了.

  5. 通过这两组点, 我们能够使用OpenCV函数 getAffineTransform 来求出仿射变换:

    warp_mat = getAffineTransform( srcTri, dstTri );

    我们获得了用以描述仿射变换的 2X3 矩阵 (在这里是 warp_mat)

  6. 将刚刚求得的仿射变换应用到源图像

    warpAffine( src, warp_dst, warp_mat, warp_dst.size() );

    函数有以下参数:

    • src: 输入源图像
    • warp_dst: 输出图像
    • warp_mat: 仿射变换矩阵
    • warp_dst.size(): 输出图像的尺寸

    这样我们就获得了变换后的图像! 我们将会把它显示出来. 在此之前, 我们还想要旋转它...

  7. 旋转: 想要旋转一幅图像, 你需要两个参数:

    1. 旋转图像所要围绕的中心
    2. 旋转的角度. 在OpenCV中正角度是逆时针的
    3. 可选择: 缩放因子

    我们通过下面的代码来定义这些参数:

    Point center = Point( warp_dst.cols/2, warp_dst.rows/2 ); double angle = -50.0; double scale = 0.6;

  8. 我们利用OpenCV函数 getRotationMatrix2D 来获得旋转矩阵, 这个函数返回一个 2X3  矩阵 (这里是 rot_mat)

    rot_mat = getRotationMatrix2D( center, angle, scale );

  9. 现在把旋转应用到仿射变换的输出.

    warpAffine( warp_dst, warp_rotate_dst, rot_mat, warp_dst.size() );

  10. 最后我们把仿射变换和旋转的结果绘制在窗体中,源图像也绘制出来以作参照:

namedWindow( source\_window, CV\_WINDOW\_AUTOSIZE );
1imshow( source\_window, src ); 2 3namedWindow( warp\_window, CV\_WINDOW\_AUTOSIZE ); 4imshow( warp\_window, warp\_dst ); 5 6namedWindow( warp\_rotate\_window, CV\_WINDOW\_AUTOSIZE ); 7imshow( warp\_rotate\_window, warp\_rotate\_dst );

11. 等待用户退出程序

waitKey(0);
点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )

mysql设置时区

mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0

OpenCV实现仿射变换 - HelloWorld