投影协方差
在之前的文章中,我们已经成功地将 3D 高斯的均值(Means,即位置
此篇文章的核心目标,就是将 3D 协方差投影到 2D 平面上,也就是求出
将 3D 协方差投影到 2D 的数学公式如下:
这个公式看着吓人,但我们在代码里其实只需要拆解成三步:
1.
2.
3. 连乘:把它们和原始的 3D 协方差
为什么需要雅可比矩阵 J ?
在相机坐标系中,从 3D 点映射到 2D 像素坐标的“透视投影(Perspective Projection)”是一个非线性变换(因为计算时需要除以深度
如果我们对一个高斯分布进行非线性变换,投影出来的结果就不再是标准的高斯分布了。为了在 2D 平面上依然能够用椭圆(2D 高斯)来近似渲染,我们需要在 3D 高斯的中心点处,利用一阶泰勒展开对非线性的透视投影进行线性近似(仿射变换)。
求取这个线性近似的导数矩阵,也就是在求雅可比矩阵
假设 3D 高斯的中心点在世界坐标系下为
首先,通过视图矩阵
接下来,我们需要将相机坐标系下的点
其中,
雅可比矩阵
将计算得到的所有偏导数代入矩阵中,我们就得到了最终的核心雅可比矩阵
代码实现
首先我们需要得到世界到相机的变换矩阵 W。代码中我们已有“相机到世界(Camera to World, C2W)”的变换。我们需要提取其左上角的旋转部分,并对其进行转置,就能得到“世界到相机(World to Camera)”的旋转矩阵。
- # W: 从世界坐标系到相机坐标系的变换矩阵
- W = camera2world[:3, :3].T
接着我们构建雅可比矩阵。我们先初始化一个全零矩阵,然后填入我们推导出的偏导数。
- # 构建雅可比矩阵 J
- J = torch.zeros((N, 2, 3), device=pos.device, dtype=pos.dtype)
- J[:, 0, 0] = fx / z_cam
- J[:, 1, 1] = fy / z_cam
- J[:, 0, 2] = -(fx * x_cam) / (z_cam ** 2)
- J[:, 1, 2] = -(fy * y_cam) / (z_cam ** 2)
现在我们有了
- # 矩阵乘法
- TMP = W.unsqueeze(0) @ sigma @ W.unsqueeze(0).transpose(1, 2)
- sigma_camera = J @ TMP @ J.transpose(1, 2)