![机器学习数学基础](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=1739255788-EYyl2fsVRqc5WrZLotVowW6kHZLyTt0t-0-f3baac5a3762a22bdf664cf6cfa32ff0)
![](https://epubservercos.yuewen.com/39156C/23020656909779806/epubprivate/OEBPS/Images/txt002_401.jpg?sign=1739255788-XbhSxaPWpn6y2ieyLcsdI3o6rwST9vBE-0-e72b6c51199296c91879e09c5292bf9b)
图2-2-10
既然平移不是线性变换,当然就不能用矩阵乘法的形式表示。然而在计算机图形学中,旋转、缩放、平移又是三种非常经典且常用的图形变换,旋转、缩放用矩阵乘法形式表示,偏偏平移不能,这从形式上看不美,且不便于计算和操作。为了解决这个问题,数学家们引入了齐次坐标系,这是一种与笛卡儿坐标系完全不同的坐标系形式,还是以平面空间为例,在笛卡儿坐标系中,每个点可以用的形式表示,在齐次坐标系中,则变成了
,其中
。通常,可以设
(关于齐次坐标系的详细内容,读者可以参考计算机图形学有关资料)。
利用齐次坐标系,图2-2-10所示的平移就可以写成:
![](https://epubservercos.yuewen.com/39156C/23020656909779806/epubprivate/OEBPS/Images/txt002_406.jpg?sign=1739255788-5gV89yX5MgZ0e7WVep8l0W8y8z4QnO5R-0-dcc87ebc063dcaaa4108eae825023dce)
![](https://epubservercos.yuewen.com/39156C/23020656909779806/epubprivate/OEBPS/Images/txt002_407.jpg?sign=1739255788-ZCrwW74Q77D2CCiolQoocKqxGLjhROs6-0-7f335effd3e06cbb99ebbcfa85a1983a)
这样,平移也可以用矩阵乘法形式表示了。还是注意,这本质上不是线性变换,只不过创建齐次坐标系之后,可以使用线性变换的形式。
对于二维向量空间的齐次坐标系,以下几个矩阵分别是实现了齐次坐标中的旋转、伸缩、平移变换(如图2-2-11所示):
● 旋转:,
表示旋转的角度
● 伸缩:,
表示伸缩的倍数
● 平移:,
,
分别为
、
移动的长度
对于某个向量分别实施伸缩、旋转、平移变换,则可写成:
![](https://epubservercos.yuewen.com/39156C/23020656909779806/epubprivate/OEBPS/Images/txt002_417.jpg?sign=1739255788-jhOBOm6SjnYdDJXanqoQuj0CmbyUbQ94-0-fcb0063355124212b624c429af6b290c)
![](https://epubservercos.yuewen.com/39156C/23020656909779806/epubprivate/OEBPS/Images/txt002_418.jpg?sign=1739255788-nH1Cr7R7Rr1EsqV3ezJlFXYwQOGKD0fD-0-bf586705662c4858197d68f3a19b5417)
图2-2-11
对于图2-2-11中的,如果要让它连续完成“伸缩→旋转→平移”变换之后,最后变成
,用
实现:
![](https://epubservercos.yuewen.com/39156C/23020656909779806/epubprivate/OEBPS/Images/txt002_422.jpg?sign=1739255788-ESqKKQdLxEF94QQgasImJ1Kjdf44moYi-0-85fb929791a27de09004b54bfd5d7eed)
设,则:
![](https://epubservercos.yuewen.com/39156C/23020656909779806/epubprivate/OEBPS/Images/txt002_424.jpg?sign=1739255788-gU8r0gq8VzM3tglN643RMa7pmRjLWNGA-0-051eb2c7bc941964a167a23dc7d6cc6d)
于是:
![](https://epubservercos.yuewen.com/39156C/23020656909779806/epubprivate/OEBPS/Images/txt002_425.jpg?sign=1739255788-Pq1OPYNhOXKMIe9WsMiUMIhEsiAELV7K-0-91b8e4ef01e0cae4de1fd59625195c66)
即:。
如前所述,缩放、旋转是线性变换,但平移不是。如果将线性变换和平移综合起来,统称这类变换为仿射变换(Affine Transformation)。常见的仿射变换,除了缩放、旋转和平移之外,还包括反射和剪切。
以上以手工计算的方式演示了图形变换的基本原理,在程序中,我们会使用一些库和模块实现各种图形变换。下面以目前常用的OpenCV为例,演示图形的平移、缩放和旋转变换。
1.平移
![](https://epubservercos.yuewen.com/39156C/23020656909779806/epubprivate/OEBPS/Images/txt002_427.jpg?sign=1739255788-58Uo2bfdMqYtxhLoAJQAETG1L7mnBw6h-0-f795911fbaf8c889ea43f821b8bf6821)
输出图像:
![](https://epubservercos.yuewen.com/39156C/23020656909779806/epubprivate/OEBPS/Images/txt002_428.jpg?sign=1739255788-KP0Gm97fwUj8qqJLy7z6mOURqeweVdYv-0-32d319909b6a54bad8da15b49ca1adce)
在上述程序中,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=1739255788-PXRYWEvdSgTq3YQhihWLFf1CEJijTaW5-0-3a16fc71a5af39ae0b375f5adfb7df07)
输出图像:
![](https://epubservercos.yuewen.com/39156C/23020656909779806/epubprivate/OEBPS/Images/txt002_432.jpg?sign=1739255788-9kSywhENe6PhgzhHmY9CZlxaZ6nEjWxn-0-67d6425b6d110338c03be45717763596)
在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=1739255788-06B1MWDZCzyYlKjnJ8i6h33O4JzzUfVx-0-7e46de5a1882718fed379aa407a704f5)
输出图像:
![](https://epubservercos.yuewen.com/39156C/23020656909779806/epubprivate/OEBPS/Images/txt002_435.jpg?sign=1739255788-jeJQ8D9FfCC2dUkGVCXJ1uIsS3QfpxaF-0-34d04cd01a6e4f38a747c83f79bfcff1)
从输出结果中可以看出,上述旋转是以原始图像的坐标原点(注意:计算机图形中坐标原点在左上角)为旋转中心,旋转了45°。为了避免此种情况,可以使用OpenCV中的专有函数构造旋转变换矩阵,如以下程序所示。
![](https://epubservercos.yuewen.com/39156C/23020656909779806/epubprivate/OEBPS/Images/txt002_436.jpg?sign=1739255788-fLbyqA0EHTrd5ULHuyuQaf0BrESVND9P-0-0210a2444834f371015496e1b08f66e8)
输出图像:
![](https://epubservercos.yuewen.com/39156C/23020656909779806/epubprivate/OEBPS/Images/txt002_437.jpg?sign=1739255788-2SAxeAsjRmOeGFoMxWvk6dtfaZTihPWi-0-738d42a398485b0dac667e77097b39ce)
函数getRotationMatrix2D(center,angle,scale)可以设置旋转中心(center)、旋转角度(angle)和缩放比例(scale)。
以上简要介绍了OpenCV中的实现旋转、缩放、平移三种变换的函数,除了这三种变换之外,OpenCV还支持其他形式的变换,比如对应点变换(用函数cv2.getAffineTransform 构造变换矩阵)等。读者若对计算机视觉或计算机图形学有兴趣,不妨深入研习OpenCV的有关应用。
如果用深度学习框架训练模型,则往往需要大量的数据,但是很多真实业务中,数据量并不充足,此时常常需要采取一些方式扩充数据。对于图像数据而言,比较简单的数据扩充方式包括图像水平翻转、尺度变换、旋转等。