Z
Toggle Nav

变换

变换依靠矩阵相乘,以往我们学习线性代数时,可能难以理解矩阵相乘到底有什么意义,在图形学中,矩阵相乘的效果就是对某一矩阵应用一种变换,例如平移、缩放、旋转等,矩阵相乘的结果,就是对原矩阵应用某种变换产生的新矩阵。

缩放变换

我们首先来以缩放这一简单的变换来说明矩阵是如何进行变换的。

在原点 \((0,\ 0)\) 处放置了一张微软logo,图中左侧坐标系中logo的大小是 \(4\times 4\) ,右侧坐标系中logo的大小是 \(8\times 8\) ,放大了2倍。相对于右侧坐标系,左侧坐标系中logo的每一个点都放大了两倍,如果以 \(x, y\) 表示左侧中的每一点,以 \(x^{\prime }, y^{\prime }\) 表示右侧中的每一点,那么变换的过程就是

\[ s=2\] \[ x^{\prime } =sx\] \[ y^{\prime } =sy\]

写成矩阵形式就是

\[ \begin{pmatrix} x^{\prime }\\ y^{\prime } \end{pmatrix} =\begin{pmatrix} s & 0\\ 0 & s \end{pmatrix}\begin{pmatrix} x\\ y \end{pmatrix}\]

根据前面学过的矩阵乘法,这一计算过程与原始变换过程是相同的。可以很直观的看出来,等号右边包含 \(s\) 的矩阵,就是我们用于缩放的矩阵(二维),左上角的 \(s\) 用于缩放 \(x\) ,右下角的 \(s\) 用于缩放 \(y\) 。当然,两个 \(s\) 的值可以是不同的,使用不同的 \(s\) 就会得到拉伸或压缩的效果,例如使用下面的矩阵

\[ \begin{pmatrix} 2 & 0\\ 0 & 1 \end{pmatrix}\]

就会得到水平方向的拉伸

对称变换

在上面的图中,右侧坐标系的logo相对于左侧坐标系的logo沿 \(y\) 轴对称,根据上面的知识,我们很容易得出该对称变换的矩阵

\[ \begin{pmatrix} -1 & 0\\ 0 & 1 \end{pmatrix}\]

切变变换

在这个例子中,右侧logo好像被拽着右上角水平拉伸了一段距离,那么怎么得到它的变换矩阵呢?我们来分析一下这个变换过程。

  • \(y=0\) 时, \(x\) 坐标不变
  • \(y=1\) 时, \(x\) 坐标变为a
  • \(y\) 始终不变

以矩阵表示这个变换就是

\[ \begin{pmatrix} 1 & a\\ 0 & 1 \end{pmatrix}\]

我们分别以紫色三个点来实际验证一下

\[\begin{pmatrix} 1 & a\\ 0 & 1 \end{pmatrix}\begin{pmatrix} 0\\ 0 \end{pmatrix} =\begin{pmatrix} 0\\ 0 \end{pmatrix}\] \[\begin{pmatrix} 1 & a\\ 0 & 1 \end{pmatrix}\begin{pmatrix} 0\\ 0.5 \end{pmatrix} =\begin{pmatrix} 0.5a\\ 0.5 \end{pmatrix}\] \[\begin{pmatrix} 1 & a\\ 0 & 1 \end{pmatrix}\begin{pmatrix} 0\\ 1 \end{pmatrix} =\begin{pmatrix} a\\ 1 \end{pmatrix}\]

验证结果没有问题,说明我们的变换矩阵是正确的。

如何得到变换矩阵

从上面的三个变换例子可以看出,要得到一个变换的变换矩阵,只需要找到 \(x\) \(x^{\prime }\) \(y\) \(y^{\prime }\) 的关系即可。对于变换来说,该变换矩阵必然是应用到图像中的每一点的,那么我们只需要找几个特殊的点,寻找他们之间的关系,而这个关系必然也适用于其他所有点。

通过上面几个例子可以看出,上面几种变换都可以描述为下面的公式

\[x^{\prime } =ax+by\] \[y^{\prime } =cx+dy\] \[\begin{pmatrix} x^{\prime }\\ y^{\prime } \end{pmatrix} =\begin{pmatrix} a & b\\ c & d \end{pmatrix}\begin{pmatrix} x\\ y \end{pmatrix}\]

这种变换就称为线性变换。

齐次坐标

理解了线性变换,我们来看另一种变换

在这个变换中logo从 \((0, 0)\) 处平移至 \((1, 1)\) 处,它的变换关系为

\[x^{\prime }=x+t_{x}\] \[y^{\prime }=y+t_{y}\]

此时可以发现平移过程无法写成上面的矩阵变换形式,而是以这种形式表示

\[\begin{pmatrix} x^{\prime }\\ y^{\prime } \end{pmatrix} =\begin{pmatrix} a & b\\ c & d \end{pmatrix}\begin{pmatrix} x\\ y \end{pmatrix} +\begin{pmatrix} t_{x}\\ t_{y} \end{pmatrix}\]

对于这种形式,我们称之为仿射变换。平移变换并不属于我们上面看到的线性变换,没法写成上面的线性变换矩阵形式。但为了将这两种变换以矩阵形式统一起来,就引入了齐次坐标这一概念。

在2D平面中我们使用两个值组成的矩阵表示点或向量,例如

\[2D\ point\ or \ 2D\ vector\ =\ \begin{pmatrix} x\\ y \end{pmatrix}\]

对2D来说,齐次坐标在其上增加了一个维度

\[2D\ point\ =\ \begin{pmatrix} x\\ y\\ 1 \end{pmatrix}\] \[2D\ vector\ =\ \begin{pmatrix} x\\ y\\ 0 \end{pmatrix}\]

对点增加了一个维度,值固定为1,对向量增加了一个维度,值固定为0。要想对齐次坐标施加变换,变换矩阵的维度必然也需要加一,否则矩阵无法相乘,这样就得出了一个非常有用的特性:我们的 \(t_{x}\) \(t_{y}\) 就能放置到这个增加的维度里,而不需要单独写出

\[\begin{pmatrix} x^{\prime }\\ y^{\prime }\\ w^{\prime } \end{pmatrix} =\begin{pmatrix} 1 & 0 & t_{x}\\ 0 & 1 & t_{y}\\ 0 & 0 & 1 \end{pmatrix}\begin{pmatrix} x\\ y\\ 1 \end{pmatrix} =\begin{pmatrix} x+t_{x}\\ y+t_{y}\\ 1 \end{pmatrix}\]

上面的例子中我们对齐次坐标应用了一个变换矩阵,在变换矩阵新增的维度上包含 \(t_{x}\) \(t_{y}\) ,这就是我们要的平移变换,同时目的也达到了,使用一次矩阵相乘就能得到之前需要相加的变换形式,并且一般的线性变换同样可以写成这种形式。

有一个问题,为什么齐次坐标要区分开点与向量的写法?一个值为0,一个值为1?这是因为向量是有方向的,它具有平移不变性,对一个向量随意进行平移,平移之后的向量方向是不变的,并且平移之后的向量就是原向量。

观察上面的矩阵乘法,结果中的三个维度是这么得到的

\[1\cdot x+0\cdot y+1\cdot t_{x}=x+t_{x}\] \[0\cdot x+1\cdot y+1\cdot t_{y}=y+t_{y}\] \[0\cdot x+0\cdot y+1\cdot 1=1\]

对于点来说这没问题,但对向量来说,因为其具有平移不变性,变换结果就是原向量,结果是不应该包含 \(t_{x}\) \(t_{y}\) 的,否则就打破了这一规则,所以对于向量来说增加的维度值为0,用来保护平移向量时的不变性。

不论是基于齐次坐标,还是几何理解,我们都能得出点与向量之间加减法的结果

  • 向量+向量=向量
  • 点-点=向量
  • 点+向量=点
  • 点+点=点

对于第四点特需要别说明一下,在齐次坐标体系下,两个点相加后 \(w=2\) ,这该怎么理解?答案是它仍是一个点,对于 \(w\) ,有

\[\begin{pmatrix} x\\ y\\ w \end{pmatrix} =\begin{pmatrix} x/w\\ y/w\\ 1 \end{pmatrix} ,\ \ w\neq 0\]

所以两个点相加,仍然是一个点,并且结果是这两个点的中点。

组合变换

对于上面这个变换,很容易发现它是旋转与平移的组合,想要直接得出整个过程的变换矩阵的过程是有些难度的,但我们可以将其分解,先沿原点旋转 \(45\degree\) (图形学中未做特别说明时,旋转都是以原点为中心逆时针旋转),然后进行平移,就能得到最终的结果了。

此时我们可以得出两个结论:

  • 复杂的变换可以通过简单变换的组合得到
  • 组合的顺序是很重要的,先旋转后平移和先平移后旋转会得出不同的结果,不论是从几何角度还是矩阵角度都是如此

那么组合变换如何描述为矩阵形式呢?答案是使用矩阵乘法。以 \(R_{45}\) 表示旋转矩阵, \(T_{(1,1)}\) 表示平移矩阵,那么最终的变换过程就是

\[T_{( 1,1)} \cdot R_{45}\begin{pmatrix} x\\ y\\ 1 \end{pmatrix} =\begin{pmatrix} 1 & 0 & 1\\ 0 & 1 & 1\\ 0 & 0 & 1 \end{pmatrix}\begin{pmatrix} \cos 45\degree & -\sin 45\degree & 0\\ \sin 45\degree & \cos 45\degree & 0\\ 0 & 0 & 1 \end{pmatrix}\begin{pmatrix} x\\ y\\ 1 \end{pmatrix}\]

组合变换矩阵的乘法顺序是从右到左的,也就是点先乘以旋转矩阵,然后乘以平移矩阵。如果想要再加上一个新变换,只需要在左边新增一个矩阵即可。

对于更广泛的情况,矩阵组合过程可以写为

\[A_{n}( \dotsc A_{2}( A_{1}( x))) =A_{n} \cdots A_{2} \cdot A_{1} \cdot \begin{pmatrix} x\\ y\\ 1 \end{pmatrix}\]

当组合多个矩阵变换时,乘法的顺序一定是从右到左的,由于矩阵没有交换律,但有结合律,那么我们可以将 \(A_{n} \cdots A_{2} \cdot A_{1}\) 计算为一个矩阵,它就表示原先我们要组合的多个矩阵。

三维变换

三维变换其实就是二维的扩展,它同样拥有齐次坐标,二维变换的一系列规则。

\[3D\ point\ =\ \begin{pmatrix} x\\ y\\ z\\ 1 \end{pmatrix}\] \[3D\ vector\ =\ \begin{pmatrix} x\\ y\\ z\\ 0 \end{pmatrix}\] \[\begin{pmatrix} x\\ y\\ z\\ w \end{pmatrix} =\begin{pmatrix} x/w\\ y/w\\ z/w\\ 1 \end{pmatrix} ,\ \ w\neq 0\] \[\begin{pmatrix} x^{\prime }\\ y^{\prime }\\ z^{\prime }\\ 1 \end{pmatrix} =\begin{pmatrix} a & b & c & t_{x}\\ d & e & f & t_{y}\\ g & h & i & t_{z}\\ 0 & 0 & 0 & 1 \end{pmatrix}\begin{pmatrix} x\\ y\\ z\\ 1 \end{pmatrix}\]