Camera-to-World

在 3D 图形学中,我们不能仅仅依靠相机本身的视角来定位物体。因为相机会平移、会旋转,如果以相机中心为原点(相机坐标系),整个世界就都在跟着乱晃。我们需要一个固定不变的参考系——世界坐标系(World Coordinate System)。


变换矩阵

我们需要在“世界”和“相机”之间建立一座桥梁。这座桥梁就是变换矩阵(Transformation Matrix)。

相机到世界矩阵 (Camera-to-World Matrix)

这个矩阵描述了相机在世界中的位置和姿态。它是一个 4 \times 4 的矩阵。

  • 左上角的 3 \times 3 区域 (R):负责旋转(Rotation)。它决定了相机是朝前看、朝天上看,还是歪着头看。
  • 最后一列的前3个元素 (t):负责平移(Translation)。它代表了相机在世界坐标系中的 x, y, z 具体位置。
  • 最后一行:永远是 [0, 0, 0, 1],为了数学运算上的补齐(构建齐次坐标)。

\text{camera2world} = \begin{bmatrix} R_{3 \times 3} & t_{3 \times 1} \\ 0_{1 \times 3} & 1 \end{bmatrix}

世界到相机矩阵 (World-to-Camera Matrix)

我们的点云原本是用世界坐标系的 (x, y, z) 表示的。但后续的光栅化公式必须在相机坐标系下计算。因此,我们需要把相机到世界的矩阵反转过来,变成“世界到相机”。

将一个点从相机坐标系转换到世界坐标系,公式为:

P_w = R \cdot P_c + t

  • R:相机到世界的旋转矩阵。
  • t:相机到世界的平移向量。

现在,我们的目标是把上面的等式反过来,也就是已知 P_w,求 P_c

首先,把 t 移到等号左边:

P_w - t = R \cdot P_c

接着,在等式两边同时左乘 R 的逆矩阵 R^{-1},把 P_c 提取出来:

R^{-1} \cdot (P_w - t) = R^{-1} \cdot R \cdot P_c

把括号展开,我们得到:

P_c = R^{-1} \cdot P_w - R^{-1} \cdot t


代码实现

理论懂了,接下来进行代码编写。我们要用 PyTorch 进行矩阵乘法,完成坐标系的转换。

假设我们的点云数据 PC 形状是 N \times 3(代表 N 个点,每个点有 x, y, z 三个坐标),而我们的 camera2world 矩阵是一个 4 \times 4 的矩阵。

第一步:构建世界到相机矩阵 (World-to-Camera Matrix)

要将物体投影到相机视野中,我们首先需要从输入的相机到世界矩阵 (camera2world) 中,推导出 世界到相机矩阵 (world2camera)。

  1. # 1. 从 camera2world 提取旋转 R 和平移 t
  2. R = camera2world[:3, :3]
  3. t = camera2world[:3, 3]
  4.  
  5. # 2. 计算 R 的转置
  6. R_t = R.t()
  7.  
  8. # 3. 计算世界到相机转换的平移向量:t_w2c = -R_t @ t
  9. t_w2c = -R_t @ t
  10.  
  11. # 4. 构造世界到相机的变换矩阵 world2camera
  12. world2camera = torch.eye(4, dtype=camera2world.dtype, device=camera2world.device)
  13. world2camera[:3, :3] = R_t
  14. world2camera[:3, 3] = t_w2c

第二步:构建齐次坐标

我们构造出来的 world2camera 变换矩阵是 4 \times 4 的,而我们的点云数据 PC 形状是 N \times 3

根据矩阵乘法“前列等于后行”的规则,我们无法直接用 4 \times 4 乘上 N \times 3。因此,我们需要构建齐次坐标:给点云的每个坐标加上一个尾巴 1,把 (x, y, z) 变成 (x, y, z, 1),使点云矩阵的形状变为 N \times 4

  1. # 5. 点云拼上最后一列 1
  2. ones = torch.ones((PC.shape[0], 1), dtype=PC.dtype, device=PC.device)
  3. PC_homo = torch.cat([PC, ones], dim=1)

第三步:执行矩阵乘法与空间变换

现在我们有了 4 \times 4 的变换矩阵 world2camera,以及 N \times 4 的齐次点云 PC_hom。为了进行矩阵乘法:

  • 我们先将点云转置,使其形状变为 4 \times N
  • 执行矩阵乘法:(4 \times 4) \times (4 \times N) \rightarrow 结果形状为 4 \times N
  • 再次转置回来,恢复为 N \times 4
  • 最后舍弃最后一列(即没用的尾巴),只保留全新的前三列 (x, y, z),恢复到 N \times 3 的形状。
  1. # 6. 利用变换矩阵变换点云
  2. PC_cam = (world2camera @ PC_homo.t()).t()[:, :3]

同样我们改变相机位置,进行可视化验证。完整的可视化代码可以查看 Commit 89087d7:visualize_camera_transformation.py