![机器学习数学基础](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=1738881973-riAjmFiBnRONmLqdjwja8PskR39SbsZ9-0-ea797eb6e6d2195729d10612d1d5e441)
![](https://epubservercos.yuewen.com/39156C/23020656909779806/epubprivate/OEBPS/Images/txt002_401.jpg?sign=1738881973-RvM8rJBKj9ToGLbjdr82XgV3z3sQEcbc-0-985908dee47c135dcc730e378c88bcd1)
图2-2-10
既然平移不是线性变换,当然就不能用矩阵乘法的形式表示。然而在计算机图形学中,旋转、缩放、平移又是三种非常经典且常用的图形变换,旋转、缩放用矩阵乘法形式表示,偏偏平移不能,这从形式上看不美,且不便于计算和操作。为了解决这个问题,数学家们引入了齐次坐标系,这是一种与笛卡儿坐标系完全不同的坐标系形式,还是以平面空间为例,在笛卡儿坐标系中,每个点可以用的形式表示,在齐次坐标系中,则变成了
,其中
。通常,可以设
(关于齐次坐标系的详细内容,读者可以参考计算机图形学有关资料)。
利用齐次坐标系,图2-2-10所示的平移就可以写成:
![](https://epubservercos.yuewen.com/39156C/23020656909779806/epubprivate/OEBPS/Images/txt002_406.jpg?sign=1738881973-wrqwa8yE1b4fnV4hnKCNrULQMzRZpGjL-0-3bf6d758c1a57036b4716440a57a86a6)
![](https://epubservercos.yuewen.com/39156C/23020656909779806/epubprivate/OEBPS/Images/txt002_407.jpg?sign=1738881973-VXZdIE1yb3E5IjfRWhMD26Qo1TvZUfPq-0-2842abe44163beddef321a57a2ed637a)
这样,平移也可以用矩阵乘法形式表示了。还是注意,这本质上不是线性变换,只不过创建齐次坐标系之后,可以使用线性变换的形式。
对于二维向量空间的齐次坐标系,以下几个矩阵分别是实现了齐次坐标中的旋转、伸缩、平移变换(如图2-2-11所示):
● 旋转:,
表示旋转的角度
● 伸缩:,
表示伸缩的倍数
● 平移:,
,
分别为
、
移动的长度
对于某个向量分别实施伸缩、旋转、平移变换,则可写成:
![](https://epubservercos.yuewen.com/39156C/23020656909779806/epubprivate/OEBPS/Images/txt002_417.jpg?sign=1738881973-FZ6hwbwxTgZOhRo489EohWEjWMFEN0AU-0-e779e45069084bcb8664893b334085f6)
![](https://epubservercos.yuewen.com/39156C/23020656909779806/epubprivate/OEBPS/Images/txt002_418.jpg?sign=1738881973-MC4BCLyIg04T63tQWj068IssfBhY3CiA-0-27c72f73d4be76a13431dcb142d87aa4)
图2-2-11
对于图2-2-11中的,如果要让它连续完成“伸缩→旋转→平移”变换之后,最后变成
,用
实现:
![](https://epubservercos.yuewen.com/39156C/23020656909779806/epubprivate/OEBPS/Images/txt002_422.jpg?sign=1738881973-0DehFQ1d3W9hlyCbM9fMlZoVrxBixiFS-0-d5c6bbb1260c60bb1c7bcfeb77717153)
设,则:
![](https://epubservercos.yuewen.com/39156C/23020656909779806/epubprivate/OEBPS/Images/txt002_424.jpg?sign=1738881973-LyiJaL4mKDEDwsOdX27Pn3JVr4enoESd-0-44709d433ca6f3a67e0b86de924f5796)
于是:
![](https://epubservercos.yuewen.com/39156C/23020656909779806/epubprivate/OEBPS/Images/txt002_425.jpg?sign=1738881973-pojrp1gDeEFaOGJlCQCbkd9mViCieNUE-0-e018cbde6896126d901a3ec4ef0331d1)
即:。
如前所述,缩放、旋转是线性变换,但平移不是。如果将线性变换和平移综合起来,统称这类变换为仿射变换(Affine Transformation)。常见的仿射变换,除了缩放、旋转和平移之外,还包括反射和剪切。
以上以手工计算的方式演示了图形变换的基本原理,在程序中,我们会使用一些库和模块实现各种图形变换。下面以目前常用的OpenCV为例,演示图形的平移、缩放和旋转变换。
1.平移
![](https://epubservercos.yuewen.com/39156C/23020656909779806/epubprivate/OEBPS/Images/txt002_427.jpg?sign=1738881973-u9qbAjX49BljP1yugUxqU8RLSc0n9q0n-0-850ab8c0fbf28d86b3bbda3c32181348)
输出图像:
![](https://epubservercos.yuewen.com/39156C/23020656909779806/epubprivate/OEBPS/Images/txt002_428.jpg?sign=1738881973-AipD5Yn5j3RzHvOCx0JeOK1toafMhWzp-0-b204c94453a50a795dc80f8c592bab69)
在上述程序中,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=1738881973-MvucTNLc8uKluqUI4OcE0L5VqaT5Lj9H-0-d43849a797db40daaca7d57891b33447)
输出图像:
![](https://epubservercos.yuewen.com/39156C/23020656909779806/epubprivate/OEBPS/Images/txt002_432.jpg?sign=1738881973-4V35ttZIEX256BIkFU2kj4akGmR8JANg-0-9f23e3e1b6d96303e174779bc0edbdba)
在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=1738881973-UdFaxBepTJzuagOtAi4clWIVWyqJSv5r-0-9bd55aa0d3fbcb6bb424ded2a97c9b7f)
输出图像:
![](https://epubservercos.yuewen.com/39156C/23020656909779806/epubprivate/OEBPS/Images/txt002_435.jpg?sign=1738881973-J4KDMgrs3qPl90aHqizyp1UWcQTcodIR-0-be2487a8e69c97451d1dc2e44b249e54)
从输出结果中可以看出,上述旋转是以原始图像的坐标原点(注意:计算机图形中坐标原点在左上角)为旋转中心,旋转了45°。为了避免此种情况,可以使用OpenCV中的专有函数构造旋转变换矩阵,如以下程序所示。
![](https://epubservercos.yuewen.com/39156C/23020656909779806/epubprivate/OEBPS/Images/txt002_436.jpg?sign=1738881973-PqJM4hiCgnd3IikGBmHWHoe38SUSneA7-0-5137da50f46a17f1ecbb3b3069cd1e97)
输出图像:
![](https://epubservercos.yuewen.com/39156C/23020656909779806/epubprivate/OEBPS/Images/txt002_437.jpg?sign=1738881973-no4NH3Co3O7QeyoO7PL6hOyNqXvaub9V-0-0798fdd0d87e512a1e630af8b0df348a)
函数getRotationMatrix2D(center,angle,scale)可以设置旋转中心(center)、旋转角度(angle)和缩放比例(scale)。
以上简要介绍了OpenCV中的实现旋转、缩放、平移三种变换的函数,除了这三种变换之外,OpenCV还支持其他形式的变换,比如对应点变换(用函数cv2.getAffineTransform 构造变换矩阵)等。读者若对计算机视觉或计算机图形学有兴趣,不妨深入研习OpenCV的有关应用。
如果用深度学习框架训练模型,则往往需要大量的数据,但是很多真实业务中,数据量并不充足,此时常常需要采取一些方式扩充数据。对于图像数据而言,比较简单的数据扩充方式包括图像水平翻转、尺度变换、旋转等。