第十章 投影

目前,我们已经在三维空间中描述了物体(objects)和视点(eye)。我们下一步的目标,是要理解如何将这些描述信息,转换为一张从视点处观察看到的二维图像。为此,我们需要建立一个简单的摄影机模型。通篇我们假设摄影机位于视点坐标系(et \vec{\mathbf{e}}^t)的原点,并且看向视点的负z z轴方向。我们使用[xe,ye,ze,1]t [x_e, y_e, z_e, 1]^t记号来表示视点坐标系下的一点。

10.1 针孔相机

最简单的摄影机形式是针孔相机(图10.1)。光线朝着摄影机的成像面运动,大部分会被一个位于ze=0 z_e = 0的不透光平面所阻挡。但是,我们在该平面的中心设置一个非常小的孔洞,它位于视点坐标系的[0,0,0,1]t [0, 0, 0, 1]^t处。

在真实的物理世界中,任何真实的相机都需要具有一个有限大小的光圈,从而定量的可被测量的光能够从光圈中通过,并抵达摄影机成像面。并且,一旦光圈是有限大小的量,就需要一个镜头来辅助更好的将入射光“组织”并聚焦。不过,这些问题现在并不对我们造成困扰,因为我们不是要依据物理法则制造真实的相机。第 21 章有关于此话题更详细的内容。

在针孔相机中,摄影机成像面上的数据需要进行翻转,才能得到我们想要的照片。从数学角度看,通过将针孔相机与摄影机成像面置于针孔的前方,例如ze=1 z_e = -1平面(图10.2),我们可以省略掉翻转图像这个步骤。在真实世界中,这是不现实的,但对于针孔相机的数学模型来说,这样做完全可行。

当创建好图像之后,如果我们将它固定在ze=1 z_e = -1平面,并且在原点处观察(图10.3),对我们来说观察到的结果会与直接观察原始场景相同。我们精确再现了从原点处观察场景时,抵达我们眼部的数据。如果在空间中移动这幅图像,例如离眼睛近一点或远一点,我们就不再精确再现原始场景的视觉刺激信息了,但是它仍旧会看起来是一个视觉上可信的原始场景。

10.2 基础数学模型

针孔相机在数学上非常容易建模。我们使用坐标系[xn,yn]t [x_n, y_n]^t来表示摄影机成像面上的点。目前,我们在摄影机成像面上选定了一个二维坐标系统,它恰好与视点坐标系相匹配(也就是,xn=xex_n = x_eyn=yey_n=y_e),但是我们很快会放宽这一设定。

给定空间中一点 pp 在视点坐标系下的坐标 [xe,ye,ze,1]t[x_e, y_e, z_e, 1]^t,可以轻易看出(根据相似三角形定理)从点p p 射向原点的射线,与成像面相交的位置为:

xn=xeze(10.1) x_n = - \frac{x_e}{z_e} \tag{10.1}
yn=yeze(10.2) y_n = - \frac{y_e}{z_e} \tag{10.2}

我们可以将其用矩阵运算表达为:

[100001000010][xeyeze1]=[xcycwc]=[xnwnynwnwn](10.3) \left[ \begin{matrix} 1 & 0 & 0 & 0 \\ 0 &1 & 0 & 0 \\ - & - & - & - \\ 0 & 0 & -1 & 0 \end{matrix} \right] \left[ \begin{matrix} x_e \\ y_e \\ z_e \\ 1 \end{matrix} \right] = \left[ \begin{matrix} x_c \\ y_c \\ - \\ w_c \end{matrix} \right] = \left[ \begin{matrix} x_nw_n \\ y_nw_n \\ - \\ w_n \end{matrix} \right] , \tag{10.3}

其中横线(—)意味着“我们不关心此处的值”。这个矩阵称作投影矩阵(projection matrix)。矩阵相乘的原始输出,[xc,yc,,wc]t [x_c, y_c, -, w_c]^t,称作点 p~ \tilde{p}裁切坐标系向量(clip coordinates)。(如此命名,是因为这个原始数据随后会在裁切阶段使用,是第12.1节的内容)。wn=wc w_n = w_c 是一个新的变量,称作w w分量(w w-coordinate)。在这样的裁切坐标空间里,第四个分量不一定必须为 0 或 1。

我们说 xnwn=xc x_nw_n = x_c,并且 ynwn=yc y_nw_n = y_c。如果想要单独提取 xn x_n,必须进行除法 xn=xnwnwn x_n = \frac{x_nw_n}{w_n},(对 yn y_n 也是这样)。当这么做的时候,我们恢复了等式 10.1 中的计算,即简单摄影机模型使用的计算。(译者注:因为此时 ze=wc=wn -z_e = w_c = w_n

我们得到的附有脚标 nn 的输出坐标系向量,称作归一化设备坐标系(normalized device coordinates),因为它用与具体像素数无关的抽象单位,表达了图像上的点。在计算机图形学中,我们将所有的图像数据都维持在正则正方形内(canonical square) 1xn+11yn+1 -1 \leq x_n \leq +1,-1 \leq y_n \leq +1,并最终将其映射到屏幕上的一个窗口中。这个正方形之外的数据,不会被记录或显示。这正是我们在附录 A 中用来描述 2D OpenGL 绘制的模型。

10.3 变体

通过改变投影矩阵中的项,我们可以对摄影机的几何变换进行微调。

10.3.1 缩放

如果我们将摄影机成像面移动到 ze=n z_e= n 处,其中n n 是一个负数(图10.4),我们可以将该摄影机建模为

xn=xenzex_n = \frac{x_en}{z_e}
yn=yenzey_n = \frac{y_en}{z_e}

这样做类似于镜头上的变焦。用矩阵来表达则是

[xnwnynwnwn]=[n0000n000010][xeyeze1](10.3)\left[ \begin{matrix} x_nw_n \\ y_nw_n \\ - \\ w_n \end{matrix} \right] = \left[ \begin{matrix} -n & 0 & 0 & 0 \\ 0 & -n & 0 & 0 \\ - & - & - & - \\ 0 & 0 & -1 & 0 \end{matrix} \right] \left[ \begin{matrix} x_e \\ y_e \\ z_e \\ 1 \end{matrix} \right] \tag{10.3}

这样实际上相当于,在原先成像面位于 ze=1 z_e = -1 的相机的基础上,将记录到的图像以 n -n 为系数进行缩放,并最终只保留图像位于正则正方形内的部分(如图10.5)。因此,后面我们最好不再将归一化设备坐标系向量(normalized device coordinates),看作位于成像面上、与某一视点坐标系相吻合的坐标系,而是简单的认为它是图像平面上固有的一个坐标系。

控制缩放系数的一个好方法是,通过给定目标摄影机的垂直视场角度(field of view)来决定 n -n 。尤其是当我们想要让摄影机的视场角为 θ \theta 度的时候。这时我们就可以设定 n=1tan(θ2) -n = \frac{1}{\tan(\frac{\theta}{2})}(如图10.6),由此我们得到投影矩阵为

[1tan(θ2)00001tan(θ2)000010](10.4)\left[ \begin{matrix} \frac{1}{\tan(\frac{\theta}{2})} & 0 & 0 & 0 \\ 0 & \frac{1}{\tan(\frac{\theta}{2})} & 0 & 0 \\ - & - & - & - \\ 0 & 0 & -1 & 0 \end{matrix} \right] \tag{10.4}

我们可以直接验证,任意以原点为起点,并与负 z z 轴在垂直方向形成的夹角为 θ2 \frac{\theta}{2} 度的射线,都会被映射到成像面上正则正方形的边界上,因此,该相机的视场角是 θ \theta 度。 例如,视点坐标系向量 [0,tan(θ2),1,1]t [0, \tan(\frac{\theta}{2}), -1, 1]^t 映射到归一化设备坐标系为 [0,1]t [0, 1]^t

更通用的处理问题,我们可以用不同的水平和垂直缩放系数 sx s_xsy s_y 来分别缩放原始图像,从而得到如下的摄影机模型:

\begin{eqnarray} \left[ \begin{matrix} x_nw_n \\ y_nw_n \\ - \\ w_n \end{matrix} \right] &=& \left[ \begin{matrix} s_x & 0 & 0 & 0 \\ 0 & s_y & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 1 & 0 \end{matrix} \right] \left[ \begin{matrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ - & - & - & - \\ 0 & 0 & -1 & 0 \end{matrix} \right] \left[ \begin{matrix} x_e \\ y_e \\ z_e \\ 1 \end{matrix} \right] \\ &=& \left[ \begin{matrix} s_x & 0 & 0 & 0 \\ 0 & s_y & 0 & 0 \\ - & - & - & - \\ 0 & 0 & -1 & 0 \end{matrix} \right] \left[ \begin{matrix} x_e \\ y_e \\ z_e \\ 1 \end{matrix} \right] \end{eqnarray}

在计算机图形学中,这种不等比的缩放在处理不为正方形的屏幕窗口时会用到。假设窗口的宽大于高。在摄影机变换中,我们需要在水平方向上挤压物体,以便更宽的水平视场角可以被容纳进我们留存的正则正方形内。当数据随后映射到窗口中时,它会被相应的拉伸从而看起来没有变形。

定义 a a ,即屏幕的宽高比(aspect ratio)为它的宽度除以高度(例如以像素为单位)。我们可以将投影矩阵设置为

[1atan(θ2)00001tan(θ2)000010](10.5)\left[ \begin{matrix} \frac{1}{a\tan(\frac{\theta}{2})} & 0 & 0 & 0 \\ 0 & \frac{1}{\tan(\frac{\theta}{2})} & 0 & 0 \\ - & - & - & - \\ 0 & 0 & -1 & 0 \end{matrix} \right] \tag{10.5}

这个相机的垂直方向与等式(10.4)中保持不变,但是在生成图像时,采用了相应更宽的水平视场角。

当窗口的高大于宽,也就是 a<1 a < 1 时,我们依然可以使用等式 10.5 中的矩阵,但我们也许并不满意这样做得到的水平视场角,因为它很狭窄。如果我们希望 θ \theta 为垂直或是水平视场角中最小的那个,那么,当 a<1 a < 1 时,我们需要使用如下的投影矩阵:

[1tan(θ2)0000atan(θ2)000010](10.5)\left[ \begin{matrix} \frac{1}{\tan(\frac{\theta}{2})} & 0 & 0 & 0 \\ 0 & \frac{a}{\tan(\frac{\theta}{2})} & 0 & 0 \\ - & - & - & - \\ 0 & 0 & -1 & 0 \end{matrix} \right] \tag{10.5}

这正是在 6.2 小节中我们调用 makeProjection 所产生的矩阵。

在计算机图形学中,选用视场角时常常需要去平衡不同的因素。一方面,更广的视场角,例如在一个游戏环境中,可以让观察者看到四周更多的东西。另一方面,在一个典型的观察环境下(除非有人把脸直接贴在屏幕前面),屏幕只占据了观察者四周环境的很小一部分角度。在这种情况下,观察者看到的几何关系会与图像环境中的不一致(就像图 10.3 中那样),并且图像看起来会有点变形(例如球体可能显示时不是圆形)。

10.3.2 移轴

不太常见的是,也许我们会希望用 [cx,cy]t [c_x, c_y]^t 来移动 2D 归一化设备坐标系。这可以用投影矩阵建模为

\begin{eqnarray} \left[ \begin{matrix} x_nw_n \\ y_nw_n \\ - \\ w_n \end{matrix} \right] &=& \left[ \begin{matrix} 1 & 0 & 0 & c_x \\ 0 & 1 & 0 & c_y \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{matrix} \right] \left[ \begin{matrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ - & - & - & - \\ 0 & 0 & -1 & 0 \end{matrix} \right] \left[ \begin{matrix} x_e \\ y_e \\ z_e \\ 1 \end{matrix} \right] \\ &=& \left[ \begin{matrix} 1 & 0 & -c_x & 0 \\ 0 & 1 & -c_y & 0 \\ - & - & - & - \\ 0 & 0 & -1 & 0 \end{matrix} \right] \left[ \begin{matrix} x_e \\ y_e \\ z_e \\ 1 \end{matrix} \right] \end{eqnarray}

对应到摄影机上,这个矩阵就描述了一个移轴的成像面(shifted film plane)(如图10.7)。它也许看起来很罕见,但实际上,因为制造工艺以及光学的问题,大部分真实的相机内部都确实有一些微量的偏移。

在计算机图形学中,移轴相机的主要用途是平铺显示(如图10.8),我们将多个显示屏并列放置来组成一个更大的屏幕。在这种情况下,这些每一个子图像都以一个适当的移轴相机来建立数学模型。移轴的另一个应用是创建一对图像,用于单屏幕上的立体显示。

通常在计算机图形学中,表示移轴(以及缩放)的相机时,会首先给定一个近切平面 ze=n z_e = n。通过指定一个视点坐标系下,与坐标轴平行的长方形,可以在这个平面上确定一个长方形。(为了得到没有变形的输出结果,这个长方形的宽高比应该与最终的窗口相吻合。)用 l,r l, r 的值来表示这个长方形在 xe x_e 坐标轴上的左右边界,并且用 t,b t, b 来表示它在 ye y_e 坐标轴上顶和底部的边界。总的来说,这些参数描述了空间中一个 3D 视锥(frustum)的形状。穿过这个长方形并射入原点的射线,会被映射到正则正方形图像内,使用如下投影矩阵描述

[2nrl0r+lrl002ntbt+btb00010](10.6)\left[ \begin{matrix} -\frac{2n}{r-l} & 0 & \frac{r+l}{r-l} & 0 \\ 0 & -\frac{2n}{t-b} & \frac{t+b}{t-b} & 0 \\ - & - & - & - \\ 0 & 0 & -1 & 0 \end{matrix} \right] \tag{10.6}

(如图 10.9)。

10.3.3 其他

在矩阵式(10.6)左上角 2 乘 2 的区域中,留有两个零在我们的摄影机模型中没有涉及到,这是一个典型的情况。这块 2 乘 2 的区域作为一个整体,可以表示像素网格的旋转与切变。切变在真实摄影机中并不常见,在计算机图形学中也不常用。当然,我们可以围绕着摄影机的光轴来旋转整个摄影机,但是这种旋转,在最初定义视点坐标系 et\vec{\mathbf{e}}^t 时,就可以用适当的摄影机旋转来表示!

10.4 应用情境(Context)

我们所描述的投影操作是一种映射,它可以在视点坐标系下应用在任何给定的点上,从而得到该点的归一化设备坐标系。尽管在 OpenGL 中,这一映射只被应用于三角形的顶点上。一旦得到了三角形上三个顶点的归一化设备坐标系向量,通过计算图像平面上位于三角形内部的所有像素,就可以简单的得到三角形内部的点。

练习

10.1 假设我们给一个冰做的立方体拍照。将它正面的投影绘制出来,用实线表示靠前的面,用虚线表示背部的面。假设用 40,30 和 20 度的视场角来分别拍摄三张图像。摄影机的其他参数保持不变。那么以下的图像序列哪一个比较可信:

10.2 (发散思考)看以下两张照片: 你能否看出这些照片是如何拍摄的?两张照片使用的视点坐标系和投影矩阵有何不同?(提示:记住我们可以制造出移轴相机。)

(版权信息:图片来自[26],版权属于 Phillip Greenspun)

10.3 (发散思考)设 et=wtE \vec{\mathbf{e}}^t = \vec{\mathbf{w}}^tE ,且 P P 是一个摄影机矩阵,是一个任意的 4 乘 4 矩阵,且第三行以"—"填充。给定 6 个点的世界坐标以及它们的归一化设备坐标,如何计算矩阵 PE1 PE^{-1} 中的 12 个未知项?(注意:必须包含未知的缩放系数才能解出这个问题)(提示:用 0 建立一个适当的右手性齐次线性系统)

Last updated