![机器学习数学基础](https://wfqqreader-1252317822.image.myqcloud.com/cover/482/43738482/b_43738482.jpg)
2.2.4 齐次坐标系
在前面讨论线性变换的时候,我们没有提到平移。什么是平移?以二维平面为例,如图2-2-10所示,向量就是向量
平移的结果,即连接两个图形的对应点的直线平行,则两个图形是平移变换。很显然,这种平移不是线性变换——向量
所在直线并不是平面空间的子空间。尽管如此,我们可以用矩阵加法表示图2-2-10所示的平移变换:
![](https://epubservercos.yuewen.com/39156C/23020656909779806/epubprivate/OEBPS/Images/txt002_400.jpg?sign=1739922475-2LZyDFVBY7WxI90bTI3Oe77hi4Z0bWKB-0-41cebd17dbbeae8247e4d776b6bdf206)
![](https://epubservercos.yuewen.com/39156C/23020656909779806/epubprivate/OEBPS/Images/txt002_401.jpg?sign=1739922475-hGWwqVBvCaxiSMScqVbABJ1r8jB4mJOF-0-dfe1202bee5acb5ff8af5b8ce77d6bf9)
图2-2-10
既然平移不是线性变换,当然就不能用矩阵乘法的形式表示。然而在计算机图形学中,旋转、缩放、平移又是三种非常经典且常用的图形变换,旋转、缩放用矩阵乘法形式表示,偏偏平移不能,这从形式上看不美,且不便于计算和操作。为了解决这个问题,数学家们引入了齐次坐标系,这是一种与笛卡儿坐标系完全不同的坐标系形式,还是以平面空间为例,在笛卡儿坐标系中,每个点可以用的形式表示,在齐次坐标系中,则变成了
,其中
。通常,可以设
(关于齐次坐标系的详细内容,读者可以参考计算机图形学有关资料)。
利用齐次坐标系,图2-2-10所示的平移就可以写成:
![](https://epubservercos.yuewen.com/39156C/23020656909779806/epubprivate/OEBPS/Images/txt002_406.jpg?sign=1739922475-AnEvZfIlktyhUJkQoJ32U9Qd4aYcZ9Vg-0-374e04554ea4ceb24fd1baccfbd6cda1)
![](https://epubservercos.yuewen.com/39156C/23020656909779806/epubprivate/OEBPS/Images/txt002_407.jpg?sign=1739922475-b4G9RdtWS15AO4OBm3y5RUCKwLepDAhu-0-d09fd9370c73dfbf9ad5b6ba81a34fca)
这样,平移也可以用矩阵乘法形式表示了。还是注意,这本质上不是线性变换,只不过创建齐次坐标系之后,可以使用线性变换的形式。
对于二维向量空间的齐次坐标系,以下几个矩阵分别是实现了齐次坐标中的旋转、伸缩、平移变换(如图2-2-11所示):
● 旋转:,
表示旋转的角度
● 伸缩:,
表示伸缩的倍数
● 平移:,
,
分别为
、
移动的长度
对于某个向量分别实施伸缩、旋转、平移变换,则可写成:
![](https://epubservercos.yuewen.com/39156C/23020656909779806/epubprivate/OEBPS/Images/txt002_417.jpg?sign=1739922475-90pkdZJvRYChRFfqw2odCkDWrAexgndg-0-7e853170e3ee56a84b97dbd4b851c92f)
![](https://epubservercos.yuewen.com/39156C/23020656909779806/epubprivate/OEBPS/Images/txt002_418.jpg?sign=1739922475-3yMCEdVfs2wCsWtup3iJNzpwnCqdaBwk-0-31041fc512e5bda9e2f9adc9553fc4a3)
图2-2-11
对于图2-2-11中的,如果要让它连续完成“伸缩→旋转→平移”变换之后,最后变成
,用
实现:
![](https://epubservercos.yuewen.com/39156C/23020656909779806/epubprivate/OEBPS/Images/txt002_422.jpg?sign=1739922475-Ezkr6w3SztqIlMdXXVCHF6y1So48PNR3-0-5649b64933a02837a3d7d098c8cbdc63)
设,则:
![](https://epubservercos.yuewen.com/39156C/23020656909779806/epubprivate/OEBPS/Images/txt002_424.jpg?sign=1739922475-OgqhZacpDJTJMD8mS8zLjBCeMRbVdjWr-0-508ff14bd5b606e69bebbcacd2b281ac)
于是:
![](https://epubservercos.yuewen.com/39156C/23020656909779806/epubprivate/OEBPS/Images/txt002_425.jpg?sign=1739922475-x8U9CTgM5M1oUfk2uvIwEoY81IKzhXdF-0-d28bb5efeb08cefae947a9909a33ef42)
即:。
如前所述,缩放、旋转是线性变换,但平移不是。如果将线性变换和平移综合起来,统称这类变换为仿射变换(Affine Transformation)。常见的仿射变换,除了缩放、旋转和平移之外,还包括反射和剪切。
以上以手工计算的方式演示了图形变换的基本原理,在程序中,我们会使用一些库和模块实现各种图形变换。下面以目前常用的OpenCV为例,演示图形的平移、缩放和旋转变换。
1.平移
![](https://epubservercos.yuewen.com/39156C/23020656909779806/epubprivate/OEBPS/Images/txt002_427.jpg?sign=1739922475-fikDLVyu2i8kRK9NaxFXaC1bHRCx3yMd-0-b83686dc6f4c295e43480366c1551cf2)
输出图像:
![](https://epubservercos.yuewen.com/39156C/23020656909779806/epubprivate/OEBPS/Images/txt002_428.jpg?sign=1739922475-Frob8P1XKwMkurEOyfQXEfcGByjh190E-0-6d47f05fcff25a70796dcebeb3e89061)
在上述程序中,M = np.float32([[1,0,500],[0,1,1000]])是平移变换矩阵,即,只是在程序中省略了矩阵的最后一行。构造的矩阵M中,
,这就是分别在x轴和y轴方向移动距离(对照输出图像)。
OpenCV中的函数warpAffine()实现了图像按照平移矩阵的仿射变换,其函数形式是warpAffine (src,M,dsize),主要参数的含义为:
● src:需要变换的图像对象,即上述程序中的img;
● M:变换矩阵,上述程序中即为定义的平移变换矩阵M;
● dsize:变换后输出图像的大小。程序中以(rows,cols)表示输入图像的大小。
2.缩放
仿照实现平移变换的程序,构造缩放矩阵,依然使用warpAffine()函数实现变换。
![](https://epubservercos.yuewen.com/39156C/23020656909779806/epubprivate/OEBPS/Images/txt002_431.jpg?sign=1739922475-BvXqQwAUwjHAjjEtjVlunuUqR2tCGK60-0-7f50da8cbb123f4d68cd231f7de06109)
输出图像:
![](https://epubservercos.yuewen.com/39156C/23020656909779806/epubprivate/OEBPS/Images/txt002_432.jpg?sign=1739922475-TLviFwRpa8npb0cyxexIubP8YvUdRj0G-0-08acc4ebe2f59abdae64c55cf4e137b0)
在OpenCV中,还提供了专门实现缩放操作的函数cv2.resize(),如果实现以上输出效果,将上述程序中的res = cv2.warpAffine(img,C,(rows//2,cols//2))替换为res2 = cv2.resize(img,(rows//2,cols//2))即可,其中的(rows//2,cols//2)为缩放后的图像大小。
3.旋转
虽然可以按照旋转变换的矩阵形式,比如旋转角度,构建旋转矩阵,再使用warpAffine()函数实现变换,但是,这样做的结果往往不如人意。
![](https://epubservercos.yuewen.com/39156C/23020656909779806/epubprivate/OEBPS/Images/txt002_434.jpg?sign=1739922475-FCvmIgN4yUhj6dMyhHez8aqh8sbt4L6O-0-231ca49a95d2ecbbeba61422d2c780b5)
输出图像:
![](https://epubservercos.yuewen.com/39156C/23020656909779806/epubprivate/OEBPS/Images/txt002_435.jpg?sign=1739922475-QUolwIG1MUkWiqGyMXWkuqTf7hDvryfX-0-984de1dc7141db603f6d952067cc51e1)
从输出结果中可以看出,上述旋转是以原始图像的坐标原点(注意:计算机图形中坐标原点在左上角)为旋转中心,旋转了45°。为了避免此种情况,可以使用OpenCV中的专有函数构造旋转变换矩阵,如以下程序所示。
![](https://epubservercos.yuewen.com/39156C/23020656909779806/epubprivate/OEBPS/Images/txt002_436.jpg?sign=1739922475-dbFyrrGey0bCGFtIpZHHh4mBArd391qk-0-6864af812c89f691deb17f29968c669e)
输出图像:
![](https://epubservercos.yuewen.com/39156C/23020656909779806/epubprivate/OEBPS/Images/txt002_437.jpg?sign=1739922475-38QiGSoggUkMXEcVjoWsN6XKkjkjvz0g-0-4d1ea571885cc902252f5cae25d2d70a)
函数getRotationMatrix2D(center,angle,scale)可以设置旋转中心(center)、旋转角度(angle)和缩放比例(scale)。
以上简要介绍了OpenCV中的实现旋转、缩放、平移三种变换的函数,除了这三种变换之外,OpenCV还支持其他形式的变换,比如对应点变换(用函数cv2.getAffineTransform 构造变换矩阵)等。读者若对计算机视觉或计算机图形学有兴趣,不妨深入研习OpenCV的有关应用。
如果用深度学习框架训练模型,则往往需要大量的数据,但是很多真实业务中,数据量并不充足,此时常常需要采取一些方式扩充数据。对于图像数据而言,比较简单的数据扩充方式包括图像水平翻转、尺度变换、旋转等。