机器学习数学基础
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

2.2.4 齐次坐标系

在前面讨论线性变换的时候,我们没有提到平移。什么是平移?以二维平面为例,如图2-2-10所示,向量就是向量平移的结果,即连接两个图形的对应点的直线平行,则两个图形是平移变换。很显然,这种平移不是线性变换——向量所在直线并不是平面空间的子空间。尽管如此,我们可以用矩阵加法表示图2-2-10所示的平移变换:

图2-2-10

既然平移不是线性变换,当然就不能用矩阵乘法的形式表示。然而在计算机图形学中,旋转、缩放、平移又是三种非常经典且常用的图形变换,旋转、缩放用矩阵乘法形式表示,偏偏平移不能,这从形式上看不美,且不便于计算和操作。为了解决这个问题,数学家们引入了齐次坐标系,这是一种与笛卡儿坐标系完全不同的坐标系形式,还是以平面空间为例,在笛卡儿坐标系中,每个点可以用的形式表示,在齐次坐标系中,则变成了,其中。通常,可以设(关于齐次坐标系的详细内容,读者可以参考计算机图形学有关资料)。

利用齐次坐标系,图2-2-10所示的平移就可以写成:

这样,平移也可以用矩阵乘法形式表示了。还是注意,这本质上不是线性变换,只不过创建齐次坐标系之后,可以使用线性变换的形式。

对于二维向量空间的齐次坐标系,以下几个矩阵分别是实现了齐次坐标中的旋转、伸缩、平移变换(如图2-2-11所示):

● 旋转:表示旋转的角度

● 伸缩:表示伸缩的倍数

● 平移:分别为移动的长度

对于某个向量分别实施伸缩、旋转、平移变换,则可写成:

图2-2-11

对于图2-2-11中的,如果要让它连续完成“伸缩→旋转→平移”变换之后,最后变成,用实现:

,则:

于是:

即:

如前所述,缩放、旋转是线性变换,但平移不是。如果将线性变换和平移综合起来,统称这类变换为仿射变换(Affine Transformation)。常见的仿射变换,除了缩放、旋转和平移之外,还包括反射和剪切。

以上以手工计算的方式演示了图形变换的基本原理,在程序中,我们会使用一些库和模块实现各种图形变换。下面以目前常用的OpenCV为例,演示图形的平移、缩放和旋转变换。

1.平移

输出图像:

在上述程序中,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()函数实现变换。

输出图像:

在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()函数实现变换,但是,这样做的结果往往不如人意。

输出图像:

从输出结果中可以看出,上述旋转是以原始图像的坐标原点(注意:计算机图形中坐标原点在左上角)为旋转中心,旋转了45°。为了避免此种情况,可以使用OpenCV中的专有函数构造旋转变换矩阵,如以下程序所示。

输出图像:

函数getRotationMatrix2D(center,angle,scale)可以设置旋转中心(center)、旋转角度(angle)和缩放比例(scale)。

以上简要介绍了OpenCV中的实现旋转、缩放、平移三种变换的函数,除了这三种变换之外,OpenCV还支持其他形式的变换,比如对应点变换(用函数cv2.getAffineTransform 构造变换矩阵)等。读者若对计算机视觉或计算机图形学有兴趣,不妨深入研习OpenCV的有关应用。

如果用深度学习框架训练模型,则往往需要大量的数据,但是很多真实业务中,数据量并不充足,此时常常需要采取一些方式扩充数据。对于图像数据而言,比较简单的数据扩充方式包括图像水平翻转、尺度变换、旋转等。