什么是仿射变换?

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

    说明

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

      1. Point2f srcTri[3];
      2. Point2f dstTri[3];
      3.  
      4. Mat rot_mat( 2, 3, CV_32FC1 );
      5. Mat warp_mat( 2, 3, CV_32FC1 );
      6. Mat src, warp_dst, warp_rotate_dst;
    2. 加载源图像:

      1. src = imread( argv[1], 1 );
    3. 以与源图像同样的类型和大小来对目标图像初始化:

      1. warp_dst = Mat::zeros( src.rows, src.cols, src.type() );
    4. 仿射变换: 正如上文所说, 我们需要源图像和目标图像上分别一一映射的三个点来定义仿射变换:

      1. srcTri[0] = Point2f( 0,0 );
      2. srcTri[1] = Point2f( src.cols - 1, 0 );
      3. srcTri[2] = Point2f( 0, src.rows - 1 );
      4.  
      5. dstTri[0] = Point2f( src.cols*0.0, src.rows*0.33 );
      6. dstTri[1] = Point2f( src.cols*0.85, src.rows*0.25 );
      7. dstTri[2] = Point2f( src.cols*0.15, src.rows*0.7 );

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

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

      1. warp_mat = getAffineTransform( srcTri, dstTri );

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

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

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

      函数有以下参数:

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

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

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

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

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

      1. Point center = Point( warp_dst.cols/2, warp_dst.rows/2 );
      2. double angle = -50.0;
      3. double scale = 0.6;
    8. 我们利用OpenCV函数 getRotationMatrix2D 来获得旋转矩阵,
      这个函数返回一个 2X3  矩阵 (这里是 rot_mat)

      1. rot_mat = getRotationMatrix2D( center, angle, scale );
    9. 现在把旋转应用到仿射变换的输出.

      1. warpAffine( warp_dst, warp_rotate_dst, rot_mat, warp_dst.size() );
    10. 最后我们把仿射变换和旋转的结果绘制在窗体中,源图像也绘制出来以作参照:

      1. namedWindow( source_window, CV_WINDOW_AUTOSIZE );
      2. imshow( source_window, src );
      3.  
      4. namedWindow( warp_window, CV_WINDOW_AUTOSIZE );
      5. imshow( warp_window, warp_dst );
      6.  
      7. namedWindow( warp_rotate_window, CV_WINDOW_AUTOSIZE );
      8. imshow( warp_rotate_window, warp_rotate_dst );
    11. 等待用户退出程序

      1. waitKey(0);

OpenCV实现仿射变换的更多相关文章

  1. 【转】【opencv】仿射变换

    仿射变换 目标 在这个教程中你将学习到如何: 使用OpenCV函数 warpAffine 来实现一些简单的重映射. 使用OpenCV函数 getRotationMatrix2D 来获得一个  旋转矩阵 ...

  2. opencv 图像仿射变换 计算仿射变换后对应特征点的新坐标 图像旋转、缩放、平移

    常常需要最图像进行仿射变换,仿射变换后,我们可能需要将原来图像中的特征点坐标进行重新计算,获得原来图像中例如眼睛瞳孔坐标的新的位置,用于在新得到图像中继续利用瞳孔位置坐标. 仿射变换在:http:// ...

  3. OpenCV图像变换(仿射变换与透视变换)

    仿射变换(affine transform)与透视变换(perspective transform)在图像还原.图像局部变化处理方面有重要意义.通常,在2D平面中,仿射变换的应用较多,而在3D平面中, ...

  4. 【OpenCV新手教程之十八】OpenCV仿射变换 &amp; SURF特征点描写叙述合辑

    本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/33320997 作者:毛星云(浅墨)  ...

  5. 计算机视觉2D几何基元及其变换介绍和OpenCV WarpPerspective源码分析

    2D图像几何基元 一般的,表示一个2d几何基元只用两个维度(比如x,y)就可以表示了,但是在计算机视觉研究中,为了统一对2d几何基元的操作(后面讲到的仿射,透射变换),一般会以增广矢量的方式表示几何基 ...

  6. EasyPR--开发详解(5)颜色定位与偏斜扭转

    本篇文章介绍EasyPR里新的定位功能:颜色定位与偏斜扭正.希望这篇文档可以帮助开发者与使用者更好的理解EasyPR的设计思想. 让我们先看一下示例图片,这幅图片中的车牌通过颜色的定位法进行定位并从偏 ...

  7. EasyPR--开发详解

    我正在做一个开源的中文车牌识别系统,Git地址为:https://github.com/liuruoze/EasyPR. 我给它取的名字为EasyPR,也就是Easy to do Plate Reco ...

  8. opencv 用户文档 错误更正 仿射变换

    今天在看opencv官方给出的仿射变换计算仿射变换矩阵的文档的时候,发现官方文档中有个很明显的错误,再次给大家提个醒. 官方文档连接: http://opencv.willowgarage.com/d ...

  9. OpenCV探索之路(八):重映射与仿射变换

    重映射 重映射就是把一幅图像中某个位置的像素放置到另一个图片中指定位置的过程. 用一个数学公式来表示就是: 其中的 f 就是映射方式,也就说,像素点在另一个图像中的位置是由 f 来计算的. 在Open ...

随机推荐

  1. Linux中的高级文本处理命令,cut命令,sed命令,awk命令

    1.2.1 cut命令 cut命令可以从一个文本文件或者文本流中提取文本列. cut语法 [root@www ~]# cut -d'分隔字符' -f fields    ## 用于有特定分隔字符 [r ...

  2. wget 常用参数释义

    wget 大法好啊,废话不多说,下面开始wget之旅吧. 下载限速 wget命令有一个内建的选项可以先顶下载任务占有的最大的带宽,从而保证其他应用程序的流畅运行. 具体使用--limit-rate 数 ...

  3. 最近邻查找算法kd-tree

    http://blog.csdn.net/pipisorry/article/details/52186307 )选择特征(坐标轴)的方法  (2)以该特征的哪一个为界 (3)达到什么条件算法结束. ...

  4. Android View框架总结(七)View事件分发机制

    请尊重分享成果,转载请注明出处: http://blog.csdn.net/hejjunlin/article/details/52282833 View布局告一段落,从本篇开始View事件相关分析, ...

  5. 剑指Offer——回溯算法

    剑指Offer--回溯算法 什么是回溯法 回溯法实际是穷举算法,按问题某种变化趋势穷举下去,如某状态的变化用完还没有得到最优解,则返回上一种状态继续穷举.回溯法有"通用的解题法"之 ...

  6. 一个简单程序快速入门JDBC

    首先创建jdbc的库,再在这个库里面创建一张users表. drop database if exists jdbc; create database if not exists jdbc; use ...

  7. maven -Dmaven.multiModuleProjectDirectory system propery is not set. Check $M2_HOME

    遇到错误:-Dmaven.multiModuleProjectDirectory system propery is not set. Check $M2_HOME解决办法:在环境变量中设置M2_HO ...

  8. 新手推荐:Hadoop安装教程_单机/伪分布式配置_Hadoop-2.7.1/Ubuntu14.04

    下述教程本人在最新版的-jre openjdk-7-jdk OpenJDK 默认的安装位置为: /usr/lib/jvm/java-7-openjdk-amd64 (32位系统则是 /usr/lib/ ...

  9. Tomcat中定制阀门

    我们说管道机制给我们带来了更好的扩展性,Tomcat中在扩展性方面具体如何体现,这便是本节讨论的内容.从上节了解到基础阀门是必须执行的,假如你需要一个额外的逻辑处理阀门,可以添加一个非基础阀门. 我的 ...

  10. Tomcat的管道

    Tomcat中按照包含关系一共有四个容器--StandardEngine.StandardHost.StandardContext和StandardWrapper,对这四个容器的详细解析后面会涉及,请 ...