本文经过参考多个文章整理而成,感谢各位博主的无私分享。

综述

图像(2维平面)到图像(2维平面)的四种变换包括:等距变换,相似变换,仿射变换,投影变换。对图像的几何变换本质上是一种线性变换,其数学本质为 Inew=TIoldI_{new}=T{I_{old}}Inew​=TIold​,即通过变换矩阵TTT将原图上的点的位置 IoldI_{old}Iold​ 变换到新的位置,从而得到新的图像InewI_{new}Inew​。

执行一般的二维空间变换包括如下三步:

  • 定义空间变换的参数;
  • 创建变换结构体TFORM,它定义了你所要执行变换的类型;
    TFORM结构体包含了执行变换需要的所有参数。你可以定义很多类型的空间变换,包括仿射变换affine transformations(如平移translation,缩放scaling,旋转rotation,剪切shearing)、投影变换projective transformations和自定义的变换custom transformations。
    创建结构体的方法有两种:使用maketform或者使用cp2tform。
  • 执行变换。
    通过将要变换的图像和TFORM结构体传递给imtransform函数即可实现变换。


2D平面变换示意图

  • Translation 平移
  • Euclidean(rigid, rotation) 旋转
  • Scale 缩放;图中没有画出
  • Similarity 相似变换;结合旋转,平移和缩放
  • Affine 仿射变换;想象在similarity的基础上用两只手对图像进行按压拉伸
  • Projective 投影变换;想象投影仪做的事情,将一个面投影到另外一个面的情况

eometry Transformation 几何变换
Homogeneous coordinate 齐次坐标:使用N+1维坐标来表示N维坐标,例如在2D笛卡尔坐标系中加上额外变量w来形成2D齐次坐标系。齐次坐标具有规模不变性,同一点可以被无数个齐次坐标表达. 齐次坐标转化为笛卡尔坐标可以通过同除最后一项得到。

仿射变换

原理

仿射变换其实是另外两种简单变换的叠加:一个是线性变换,一个是平移变换。统一平移变换和线性变换的一种变换我们起了个名字叫“仿射变换”。这个新的变换就不再单纯的是两个线性空间的映射了,而是变成了两个仿射空间的映射关系。为了更好地理解仿射变换,首先就要知道线性变换以及它的不足。在未说明的情况下,下面使用的是卡迪尔坐标系。
所谓线性变换是指两个线性空间的映射,一个变换L:A→B{\mathcal{L}:\mathcal{A}\to\mathcal{B}}L:A→B是线性变换,必须满足两个条件,也就是我们经常说的线性条件:

  • L(u+v)=L(u)+L(v)L(u+v)=L(u)+L(v)L(u+v)=L(u)+L(v) additivity
  • L(αu)=αL(u){L({\alpha}u)={\alpha}L(u)}L(αu)=αL(u) homogeneity

举个例子说明一下。假设LLL是一个二维绕原点旋转变换,uuu和vvv是旋转角度。我们知道“一次性旋转u+vu+vu+v度”和“先旋转uuu度再旋转vvv读”达到的效果是一样的;同样地,“一次性旋转αu{\alpha}uαu度”和“旋转α\alphaα次uuu度”也是一样的。
线性变换可以用矩阵来表示。假设p=(x,y)Tp=(x,y)^{T}p=(x,y)T是二维空间中的点,TTT是一线性变换,那么存在一个矩阵AAA,使得p′=(x′,y′)T=T(p)=App'=(x',y')^{T}=T(p)=App′=(x′,y′)T=T(p)=Ap。上面的旋转变换RRR,以及缩放SSS变换都有相应的变换矩阵

[x′y′]=R(p)=[cos(θ)−sin(θ)sin(θ)cos(θ)][xy]\left[ {\begin{array}{c} x'\\y'\\ \end{array}} \right]=R(p)= \left[ {\begin{array}{cc} cos(\theta) & -sin(\theta) \\ sin(\theta) & cos(\theta) \\ \end{array} } \right] \left[ {\begin{array}{cc} x \\ y \\ \end{array} } \right][x′y′​]=R(p)=[cos(θ)sin(θ)​−sin(θ)cos(θ)​][xy​]

[x′y′]=S(p)=[Sx00Sy][xy]\left[ {\begin{array}{c} x'\\y'\\ \end{array}} \right]=S(p)= \left[ {\begin{array}{cc} S_x & 0 \\ 0 & S_y \\ \end{array} } \right] \left[ {\begin{array}{c} x \\ y \\ \end{array} } \right][x′y′​]=S(p)=[Sx​0​0Sy​​][xy​]

但是在笛卡尔坐标系中,平移变换却不能用矩阵来表示。一个平移变换TTT具有如下的形式

[x′y′]=T(p)=I[xy]+[txty]\left[ {\begin{array}{c} x'\\y'\\ \end{array}} \right]=T(p)= I \left[ {\begin{array}{cc} x \\ y \\ \end{array} } \right]+\left[ {\begin{array}{c} t_x \\ t_y \\ \end{array} } \right][x′y′​]=T(p)=I[xy​]+[tx​ty​​]

我们可以很容易地验证,平移变换TTT是不能写成两个矩阵乘积形式的。使用齐次坐标系很好的解决了这个问题(可能还有其它的原因)。齐次坐标系统其实是用高维坐标来表示一个低维的点,就好比我们用(x,1)(x,1)(x,1)来表示一个长度值一样,其实用一个xxx就可以了,但是用高一维的表示,在有的时候会带来便利。一个N维的卡迪尔坐标系中的一个点p=(x1,x2,...,xN)p=(x_1,x_2,...,x_N)p=(x1​,x2​,...,xN​),在齐次坐标系中有无数的N+1N+1N+1维点与之对应,这些点可以描述为pH=(ωx1,ωx2,...,ωxN,ω)p_H=(\omega x_1,\omega x_2,...,\omega x_N,\omega)pH​=(ωx1​,ωx2​,...,ωxN​,ω),ω\omegaω取不同的值,我们变得到齐次坐标系中不同的点。当把这些点映射到ω=1\omega=1ω=1平面(不改变xix_ixi​之间比例),我们又降维得到对应的卡迪尔坐标系中的点。在OpenGL中我们是用(x,y,z,1)(ω=1)(x,y,z,1)(\omega=1)(x,y,z,1)(ω=1)来表示一点三维的点,显然这个点与卡迪尔坐标系中的点(x,y,z)(x,y,z)(x,y,z)是一一对应的。在计算的过程中,会出现第四个分量不为ω≠1\omega \neq 1ω​=1的情况,这时我们也总是同除以ω\omegaω使齐次坐标正规化。

现在回来让我们看看使用齐次坐标时,对应的线性变换是什么形式。假设p=(x,y,1)Tp=(x,y,1)^{T}p=(x,y,1)T是二维点对应的齐次坐标,与上面使用卡迪尔坐标系类似,我们可以得到相应的线性变换如旋转变换RRR和缩放变换SSS的矩阵表示:

[x′y′1]=R(p)=[cos(θ)−sin(θ)0sin(θ)cos(θ)0001][xy1]\left[ {\begin{array}{c} x'\\y'\\1\\ \end{array}} \right]=R(p)= \left[ {\begin{array}{ccc} cos(\theta) & -sin(\theta) & 0 \\ sin(\theta) & cos(\theta) & 0 \\ 0 & 0 & 1\\\end{array} } \right] \left[ {\begin{array}{c} x \\ y \\ 1 \\ \end{array} } \right]⎣⎡​x′y′1​⎦⎤​=R(p)=⎣⎡​cos(θ)sin(θ)0​−sin(θ)cos(θ)0​001​⎦⎤​⎣⎡​xy1​⎦⎤​

[x′y′1]=S(p)=[Sx000Sy0001][xy1]\left[ {\begin{array}{c} x'\\y'\\1\\ \end{array}} \right]=S(p)= \left[ {\begin{array}{ccc} S_x & 0 & 0 \\ 0 & S_y & 0 \\ 0 & 0 & 1\\ \end{array} } \right] \left[ {\begin{array}{c} x \\ y \\ 1 \\ \end{array} } \right]⎣⎡​x′y′1​⎦⎤​=S(p)=⎣⎡​Sx​00​0Sy​0​001​⎦⎤​⎣⎡​xy1​⎦⎤​

容易验证, (x′,y′)(x', y')(x′,y′)的值并没有变化。但是使用齐次坐标后,平移操作便也可以使用矩阵来表示了(如下),平移量出现在变换矩阵的最右侧。

[x′y′1]=T(p)=[10tx01ty001][xy1]\left[ {\begin{array}{c} x'\\y'\\1\\ \end{array}} \right]=T(p)= \left[ {\begin{array}{ccc} 1 & 0 & t_x \\ 0 & 1 & t_y \\ 0 & 0 & 1\\ \end{array} } \right] \left[ {\begin{array}{c} x \\ y \\ 1 \\ \end{array} } \right]⎣⎡​x′y′1​⎦⎤​=T(p)=⎣⎡​100​010​tx​ty​1​⎦⎤​⎣⎡​xy1​⎦⎤​

最后,我们给出仿射变换稍微正式点的定义。一个仿射变换TTT,可以表示成一个线性变换AAA后平移ttt:T(p)=Ap+tT(p)=Ap+tT(p)=Ap+t,其中ppp是待变换的点齐次坐标表示。TTT可以表示成如下的形式:

T=[a11a12a13t1a21a22a23t2a31a32a33t30001]\bf{T}=\left[ {\begin{array}{cccc} a_{11}&a_{12}&a_{13}&t_1\\ a_{21}&a_{22}&a_{23}&t_2\\ a_{31}&a_{32}&a_{33}&t_3\\ 0&0&0&1\\ \end{array}} \right]T=⎣⎢⎢⎡​a11​a21​a31​0​a12​a22​a32​0​a13​a23​a33​0​t1​t2​t3​1​⎦⎥⎥⎤​

其中,A=[a11a12a13a21a22a23a31a32a33]\bf{A}=\left[ {\begin{array}{ccc} a_{11}&a_{12}&a_{13}\\ a_{21}&a_{22}&a_{23}\\ a_{31}&a_{32}&a_{33}\\ \end{array}} \right]A=⎣⎡​a11​a21​a31​​a12​a22​a32​​a13​a23​a33​​⎦⎤​表示线性变换;t=[t1t2t3]\bf{t}=\left[ {\begin{array}{c} t_1\\ t_2\\ t_3\\ \end{array}} \right]t=⎣⎡​t1​t2​t3​​⎦⎤​表示平移变换;右下角的数字可以进行整体缩放,当为1时,表示不进行整体缩放。

可以知道:仿射变换保持了二维图形的“平直性”和“平行性”。仿射变换可以通过一系列的变换的复合来实现,包括平移,缩放,翻转,旋转和剪切。

warpAffine

opencv中相应的函数是:
void warpAffine(InputArray src, OutputArray dst, InputArray M, Size dsize, int flags=INTER_LINEAR, int borderMode=BORDER_CONSTANT, const Scalar& borderValue=Scalar())
Parameters:

  • src – input image.
  • dst – output image that has the size dsize and the same type as src .
  • M – transformation matrix,本文中着重讲M的构造
  • dsize – size of the output image.ansformation ().
  • borderMode – pixel extrapolation method (see borderInterpolate()); when borderMode=BORDER_TRANSPARENT , it means that the pixels in the destination image corresponding to the “outliers” in the source image are not modified by the function.
  • borderValue – value used in case of a constant border; by default, it is 0.

典型的变换矩阵

  • 平移,将每一点移到到(x+t,y+t)(x+t , y+t)(x+t,y+t),变换矩阵为
  • 缩放变换 将每一点的横坐标放大或缩小sxs_xsx​倍,纵坐标放大(缩小)到sys_ysy​倍,变换矩阵为
    [Sx000Sy0001]\left[ {\begin{array}{ccc} S_x & 0 & 0 \\ 0 & S_y & 0 \\ 0 & 0 & 1\\ \end{array} } \right]⎣⎡​Sx​00​0Sy​0​001​⎦⎤​
  • 旋转变换原点:目标图形围绕原点顺时针旋转θ\thetaθ弧度,变换矩阵为
  • 旋转变换 :目标图形以(x,y)(x , y)(x,y)为轴心顺时针旋转θ\thetaθ弧度,变换矩阵为

    相当于两次平移与一次原点旋转变换的复合,即先将轴心(x,y)(x,y)(x,y)移到到原点,然后做旋转变换,最后将图片的左上角置为图片的原点,即

    在opencv的图像处理中,所有对图像的处理都是从原点进行的,而图像的原点默认为图像的左上角,而我们对图像作旋转处理时一般以图像的中点为轴心。

getRotationMatrix2D

可以使用opencv中自带的Mat getRotationMatrix2D(Point2f center, double angle, double scale)函数获得变换矩阵M,

  • center:旋转中心
  • angle:旋转弧度,一定要将角度转换成弧度
  • scale:缩放尺度

它得到的矩阵是:
(顺时针)

(逆时针)

其中α=scale∗cos(angle),β=scale∗sin(angle),(center.x,center.y)α = scale * cos(angle) , β = scale * sin(angle) , (center.x , center.y)α=scale∗cos(angle),β=scale∗sin(angle),(center.x,center.y) 表示旋转轴心。

getAffineTransform

opencv中还有一个函数:Mat getAffineTransform(InputArray src, InputArray dst)
它通过三组点对就可以获得它们之间的仿射变换,如果我们在一组图像变换中知道变换后的三组点,那么我们就可以利用该函数求得变换矩阵,然后对整张图片进行仿射变换。

仿射变换之所以重要,另一个重要的原因是仿射变换后不改变点的共线/共面性,而且还保持比例,这对图形系统尤其重要。例如,根据这个性质,如果我们要变换一个三角形,只需要对三个定点v1v1v1,v2v2v2,v3v3v3进行变换T就可以了,对于原先边v1v2v1v2v1v2上的点,变换后一定还在边后T(v1)T(v2)T(v1)T(v2)T(v1)T(v2)上。

总结一下,仿射变换是线性变换后进行平移变换(其实也是齐次空间的线性变换),使用齐次坐标使得仿射变换可以以统一的矩阵形式进行表示。

透视变换

还有一种与仿射变换经常混淆的变换为透视变换,透视变换需要四组点对才能确定变换矩阵,由于仿射变换保持“平直性”与“平行性”,因此只需要三组点对,而透视变换没有这种约束,故需要四组点对。

原理

透视变换(Perspective Transformation)是将图片投影到一个新的视平面(Viewing Plane),也称作投影映射(Projective Mapping)。通用的变换公式为:

uuu,vvv是原始图片左边,对应得到变换后的图片坐标xxx,yyy,其中

变换矩阵可以拆成4部分,表示线性变换,比如scaling,shearing和ratotion。用于平移,产生透视变换。所以可以理解成仿射等是透视变换的特殊形式。经过透视变换之后的图片通常不是平行四边形(除非映射视平面和原来平面平行的情况)。

重写之前的变换公式可以得到:

所以,已知变换对应的几个点就可以求取变换公式。反之,特定的变换公式也能新的变换后的图片。简单的看一个正方形到四边形的变换:
变换的4组对应点可以表示成:
根据变换公式得到:
定义几个辅助变量:
都为0时变换平面与原来是平行的,可以得到:
不为0时,得到:
求解出的变换矩阵就可以将一个正方形变换到四边形。反之,四边形变换到正方形也是一样的。于是,我们通过两次变换:四边形变换到正方形+正方形变换到四边形就可以将任意一个四边形变换到另一个四边形。

warpPerspective

主要作用:对图像进行透视变换,就是变形。
C++: void warpPerspective(InputArray src, OutputArray dst, InputArray M, Size dsize, int flags=INTER_LINEAR, int borderMode=BORDER_CONSTANT, const Scalar& borderValue=Scalar())
参数详解:

  • InputArray src:输入的图像
  • OutputArray dst:输出的图像
  • InputArray M:透视变换的矩阵
  • Size dsize:输出图像的大小
  • int flags=INTER_LINEAR:输出图像的插值方法,
    combination of interpolation methods (INTER_LINEAR or INTER_NEAREST) and the optional flagWARP_INVERSE_MAP, that sets M as the inverse transformation ( \texttt{dst}\rightarrow\texttt{src} )
  • int borderMode=BORDER_CONSTANT:图像边界的处理方式
  • const Scalar& borderValue=Scalar():边界的颜色设置,一般默认是0

参考

图像的变换
https://blog.csdn.net/liangjiubujiu/article/details/80424287

仿射变换与齐次坐标
https://blog.csdn.net/liangjiubujiu/article/details/80628506

仿射变换矩阵
https://blog.csdn.net/liangjiubujiu/article/details/80918428

matlab 二维空间变换
https://blog.csdn.net/liangjiubujiu/article/details/80607161

图像投影/单应性变换/直射
https://blog.csdn.net/liangjiubujiu/article/details/80412175

图像的等距变换,相似变换,仿射变换,射影变换及其matlab实现
https://blog.csdn.net/liangjiubujiu/article/details/80616870

仿射变换详解 warpAffine
https://blog.csdn.net/q123456789098/article/details/53330484



写于关雎



新浪微博:https://weibo.com/tianzhejia
CSDN博客:https://blog.csdn.net/qq_35605018
博客网站:http://www.zhijiadeboke.xyz
GitHub:https://github.com/ZhijiaTian
QQ邮箱:2461824656@qq.com
126邮箱:tianzhejia@126.com
Outlook邮箱:tianzhejia@outlook.com

以上均可与本人取得联系,欢迎探讨。^ v ^

[解疑]图像、矩阵的二维空间变换相关推荐

  1. matlab 二维空间变换-maketform imtransform 用法

    转自:http://blog.sina.com.cn/s/blog_6163bdeb0102du23.html 执行一般的二维空间变换包括如下三步: 1.         定义空间变换的参数: 2.  ...

  2. python 傅立叶函数_python 图像的离散傅立叶变换实例

    图像(MxN)的二维离散傅立叶变换可以将图像由空间域变换到频域中去,空间域中用x,y来表示空间坐标,频域由u,v来表示频率,二维离散傅立叶变换的公式如下: 在python中,numpy库的fft模块有 ...

  3. 图像倾斜校正 Radon 变换原理及函数

    radon校正 Radon(拉东)算法是一种通过定方向投影叠加,找到最大投影值时角度,从而确定图像倾斜角度的算法.具体过程如图所示 拉东变换 若函数F表示一个未知的密度,对F做radon变换,相当于得 ...

  4. 形象理解线性代数(三)——列空间、零空间(核)、值域、特征值(特征向量)、矩阵与空间变换、矩阵的秩

    这里,我们还是要以 形象理解线性代数(一)--什么是线性变换?为基础.矩阵对向量的作用,可以理解为线性变换,同时也可以理解为空间的变换,即(m*n)的矩阵会把一个向量从m维空间变换到n维空间. 一.矩 ...

  5. 1.2 Python图像的坐标变换-尺度变换

    1.2 Python图像的坐标变换-尺度变换 文章目录 1.2 Python图像的坐标变换-尺度变换 1 算法原理 2 代码 3 效果 1 算法原理 图像的几何变换,也就是矩阵乘法. 尺度变换是在原来 ...

  6. Matlab|数字图像处理02|图像的傅里叶变换(平移/旋转性质)及图像的离散余弦变换

    问题1:x,y方向同时平移后频谱有何变化? 答:经过平移后的傅里叶变换幅值图与原图像得到的傅里叶变换幅值图基本相同,平移不改变频谱的幅值. 代码运行结果: 代码: clc; clear all; I= ...

  7. 图像处理之图像的离散余弦变换

    一.前言 离散余弦变换(Discrete Cosine Transform, DCT)是以一组不同频率和幅值的余弦函数和来近似一幅图像,实际上是傅立叶变换的实数部分.离散余弦变换有一个重要的性质,即对 ...

  8. LabVIEW图像灰度分析与变换(基础篇—4)

    目录 1.图像灰度分析 1.1.直方图分析 1.1.1.灰度图像直方图分析 1.1.2.彩色图像直方图分析 1.2.线灰度曲线分析 1.3.图像线灰度均值分析 1.4.图像形心和质心分析 1.5.图像 ...

  9. matlab矩阵方块网络着色imshow_matlab中用imshow()显示图像与图像矩阵的数据类型的关系...

    在matlab中,我们常使用imshow()函数来显示图像,而此时的图像矩阵可能经过了某种运算.在matlab中,为了保证精度,经过了运算的图像矩阵I其数据类型会从unit8型变成double型.如果 ...

最新文章

  1. matlab清理程序onCleanup
  2. Ubantu16.04安装显卡驱动遇到的坑
  3. awk命令扩展使用操作
  4. Attempt to do update or delete on table db1.table1 that is not transactional解决
  5. Java多线程同步机制
  6. nginx负载分发情况日志输出
  7. 分布式下的session问题
  8. Python(6)-算数运算符
  9. 【Pre蓝桥杯嵌入式】如何直接使用LCD例程来作为赛场使用的工程
  10. Python自定义类调用方法
  11. linux内核中获取虚拟地址api,Linux内核-系统调用
  12. matplotlib输出图形到网页_pytorch使用matplotlib和tensorboard实现模型和训练的可视化...
  13. 2019 最新计算机技能排名出炉:Python 排第三,第一名是...
  14. 16.微信登入与授权
  15. 树莓派PICO使用MicroPython + HX1838 接收遥控器数据 NEC解码
  16. 导论计算机论文题目,计算机类论文题目
  17. 鼠标及键盘详细的键值表
  18. spring boot内嵌tomcat优雅的开启apr模式
  19. 诺基亚n1 android 6.0,数据解读诺基亚N1:安卓平板王者之争
  20. (荐)电子方面不错的论坛 推荐几个电子方面不错的论坛

热门文章

  1. SSL证书-NginX安装指南
  2. 微信企业号开发之 企业号人员身份认证与开发
  3. Paper之CVPRICCVECCV:2009年~2019年CVPRICCVECCV(国际计算机视觉与模式识别会议国际计算机视觉大会欧洲计算机视觉会议)历年最佳论文简介及其解读
  4. Android 网络框架之Retrofit源码解析,flutter边框特效
  5. 偶遇Chrome浏览器“喔唷,崩溃啦”,错误代码(STATUS_STACK_BUFFER_OVERRUN)
  6. 实验十六:电位器传感器实验
  7. Spark-SparkSession.Builder 源码解析
  8. 如何更改音频格式?分享这几个简单的转换方法给你
  9. 第二次作业:《国际贸易学》—自由贸易理论
  10. 【基于stm32 FreeRtos的智能台灯控制】