3D空间中的相机

less than 1 minute read

Published:

处理3D计算机视觉,常常就是在处理相机的问题。

Pytorch3d Cameras

Camera Coordinate Systems

对于相机,有4个坐标系: 世界坐标系:物体所处的坐标系,即真实世界。 相机坐标系:这个坐标系的原点在相机,Z轴垂直于成像平面。Pytorch3d中假设LUF:+X points left, and +Y points up and +Z points out from the image plane。在应用旋转R平移T之后就会发生从世界World到视角View的变换。 NDC坐标系:这是一个归一化的坐标系,把所有点局限在一个体Volume中,这个Volume也是这个物体或者场景中会被渲染的部份,也被熟称为view Volume,视锥体。对于一张方图,鉴于Pytorch3D的约定,(+1, +1, znear) is the top left near corner,and (-1, -1, zfar) is the bottom right far corner of the volume. 在应用了定义在NDC空间的相机投影矩阵P之后就得到了View到NDC的变换。对于非方形图,会对点进行缩放,这样使得短边的范围[-1,1],长边的范围[-u,u],这里u>1,被称作长宽比,也就是aspect ratio。 屏幕坐标系:这是另一个视锥体的表示,这里XY坐标定义在成像平面上而不是归一化空间上。左上角(0,0) ,右下角 (W,H).

世界坐标系示例

Defining Cameras in PyTorch3D

PyTorch3D中的相机通过首先将对象/场景变换到视图(通过变换R和T),然后将3D对象/场景通过投影矩阵P = K[R | T]投影到归一化空间,从而将对象/场景从世界变换到视图,其中K是内参矩阵。K中的相机参数定义了归一化空间。如果用户在NDC空间中定义相机参数,则变换将点投影到NDC。如果相机参数在屏幕空间中定义,则变换后的点在屏幕空间中。

请注意,基础CamerasBase类对坐标系没有做出任何假设。上述所有变换都是仅由R、T和K定义的几何变换。这意味着用户可以在任何坐标系和任何变换中定义相机。transform_points方法将K、R和T应用于输入点,作为一个简单的矩阵变换。然而,如果用户希望使用与PyTorch3D渲染器兼容的相机,他们需要遵守PyTorch3D的坐标系假设(见下文)。

我们提供了PyTorch3D中常见相机类型的实例化,以及用户如何灵活定义投影空间。

Interfacing with the PyTorch3D Renderer

PyTorch3D渲染器既适用于网格也适用于点云,它假设相机变换后的点,即作为光栅化器输入的点,位于PyTorch3D的NDC空间中。因此,为了获得预期的渲染结果,用户需要确保他们的3D输入数据和相机遵守这些PyTorch3D坐标系假设。PyTorch3D坐标系假设+X:左,+Y:上,+Z:从我们到场景(右手系)。关于坐标系的混淆很常见,所以我们建议您花些时间了解您的数据和它们所在的坐标系,并在使用PyTorch3D渲染器之前相应地进行转换。

以下是英文字符串的简体中文翻译: 示例相机及其如何与PyTorch3D渲染器接口,可在我们的教程中找到。

Camera Types

所有相机都继承自CamerasBase,这是一个所有相机的基类。PyTorch3D提供了四种不同的相机类型。CamerasBase定义了所有相机模型共有的方法:

OpenGL Projection Matrix

Overview

计算机显示器是一个二维表面。OpenGL渲染的3D场景必须作为二维图像投影到计算机屏幕上。使用GL_PROJECTION矩阵进行这种投影变换。首先,它将所有顶点数据从眼睛(相机)坐标系转换到裁剪坐标系。然后,通过除以裁剪坐标系的w分量,将这些裁剪坐标系也转换到归一化设备坐标系(NDC)。

因此,我们必须记住,裁剪(视锥剔除)和NDC变换都集成在GL_PROJECTION矩阵中。以下章节描述了如何从6个参数构建投影矩阵;左、右、底、顶、近和远边界值。

世界坐标系示例

请注意,截锥剔除(裁剪)是在裁剪坐标中进行的,就在除以wc之前。裁剪坐标xc、yc和zc通过与其wc进行比较来测试。如果任何裁剪坐标小于-wc,或者大于wc,则该顶点将被丢弃。 \(-w_c < x_c, y_c, z_c < w_c\)

Perspective Projection

世界坐标系示例

在透视投影中,截锥体(眼睛坐标)中的3D点映射到一个立方体(归一化设备坐标);x坐标的范围从[l, r]到[-1, 1],y坐标的范围从[b, t]到[-1, 1],z坐标的范围从[-n, -f]到[-1, 1]。

请注意,眼坐标是在右手坐标系中定义的(RUB),但NDC使用的是左手坐标系(RUF)。也就是说,在原点处的相机在眼空间中沿着-Z轴观察,但在NDC中沿着+Z轴观察。由于glFrustum()只接受近和远距离的正值,我们需要在构建GL_PROJECTION矩阵时对它们取反(这里是解释为什么标注为-n,因为n、f都是正值,代表距离人眼的绝对值,-n、-f代表在人眼坐标系里z轴上的坐标)。

在OpenGL中,眼空间中的3D点被投影到近平面(投影平面)。以下图示展示了眼空间中的点(xe, ye, ze)如何投影到近平面上的点(xp, yp, zp)。

世界坐标系示例

世界坐标系示例

这里通过近似三角形,求解投影到近平面上的坐标(xp, yp, zp)。 \(\cfrac{x_p}{x_e} = \cfrac{-n}{z_e}\)

\[x_p = \cfrac{-n \cdot x_e}{z_e} = \cfrac{n \cdot x_e}{-z_e}\] \[\cfrac{y_p}{y_e} = \cfrac{-n}{z_e}\] \[y_p = \cfrac{-n \cdot y_e}{z_e} = \cfrac{n \cdot y_e}{-z_e}\]

请注意,xp和yp都依赖于ze;它们与-ze成反比。换句话说,它们都除以-ze。这是构建GL_PROJECTION矩阵的第一个线索。在通过乘以GL_PROJECTION矩阵变换眼睛坐标后,裁剪坐标仍然是有理坐标。最终,通过除以裁剪坐标的w分量,它变成了归一化设备坐标(NDC)。(有关OpenGL变换的更多详细信息,请参阅。)

参考
Pytorch3d
OPENGL