Splatstudio 学习笔记

发布于:2024-04-14 ⋅ 阅读:(149) ⋅ 点赞:(0)

1. 3DGS 是全图的Render, 因此特地写了 full_images_datamanger.py 每个step 取出一张图像。

返回值是一张 全图的 RGB 和对应的 Camera

2. 3D GS 没有生成光线,因此 不需要指定near 和 far,即 collider是None。 但需要对3D 高斯球进行初始化:

  1. 高斯球的means (中心点的初始化): 输入点云的 坐标当作是 高斯球的中心点:
 means = torch.nn.Parameter(self.seed_points[0])  # (Location, Color)
  1. 高斯球的scale初始化, 使用KNN 算法计算每一个 点云到 最近3个点之间的 距离 distance, 对这个距离求解平均距离,以这个 ave_distance 的 log 对数的结果 当作是 scale 的初始化:
distances, _ = self.k_nearest_sklearn(means.data, 3)
distances = torch.from_numpy(distances)
# find the average of the three nearest neighbors for each point and use that as the scale
avg_dist = distances.mean(dim=-1, keepdim=True)
scales = torch.nn.Parameter(torch.log(avg_dist.repeat(1, 3)))
  1. 旋转四元数的初始化,随机初始化:
quats = torch.nn.Parameter(random_quat_tensor(num_points))
  1. opacity的初始化,随机给定一个固定数值从 0.1 初始化:
opacities = torch.nn.Parameter(torch.logit(0.1 * torch.ones(num_points, 1)))
  1. color 的SH 参数的初始化,从点云的 RGB 直接转化为 SH 系数:
if self.config.sh_degree > 0:
   shs[:, 0, :3] = RGB2SH(self.seed_points[1] / 255) ## RGB 转化成第0阶的 SH 系数
   shs[:, 1:, 3:] = 0.0
else:
   CONSOLE.log("use color only optimization with sigmoid activation")
   shs[:, 0, :3] = torch.logit(self.seed_points[1] / 255, eps=1e-10)
features_dc = torch.nn.Parameter(shs[:, 0, :])
features_rest = torch.nn.Parameter(shs[:, 1:, :])

SH 的稀疏的 shape 标准是(N,16,3); 3 代表3个通道, N 代表 N个点,16 代表阶数。

第0 阶的参数直接由RGB 转换而来; 之后都是设置为0 进行初始化。 对应的优化参数是:

features_dc = torch.nn.Parameter(shs[:, 0, :]) ## 【N,3】
features_rest = torch.nn.Parameter(shs[:, 1:, :]) ## 【N,15,3】

3. 3D GS 的属性:

 self.gauss_params = torch.nn.ParameterDict(
            {
                "means": means,  ## Location
                "scales": scales, ## 缩放因子
                "quats": quats,   ## 旋转的四元数
                "features_dc": features_dc,
                "features_rest": features_rest,
                "opacities": opacities, ## 不透明度
            }
        )

这行使用 torch 的 ParameterDict 的 代码相当于 直接使用:

self.means = means;
self.scales = scales;

3.1 首先对于整张 图像进行 DownScale 4 倍:

对图像进行4倍降采样,并修改对应的内参
camera_downscale = self._get_downscale_factor() ## 4
camera.rescale_output_resolution(1 / camera_downscale)

3.2 修改 Camera 的坐标,将其从 nerfstudio 的坐标 旋转 到 opencv 的坐标。 也就是 [-1,-1,1] 的矩阵

 # shift the camera to center of scene looking at center
R = camera.camera_to_worlds[0, :3, :3]  # 3 x 3
T = camera.camera_to_worlds[0, :3, 3:4]  # 3 x 1
# flip the z and y axes to align with gsplat conventions
R_edit = torch.diag(torch.tensor([1, -1, -1], device=self.device, dtype=R.dtype))
R = R @ R_edit
# analytic matrix inverse to get world2camera matrix
R_inv = R.T
T_inv = -R_inv @ T
viewmat = torch.eye(4, device=R.device, dtype=R.dtype)
viewmat[:3, :3] = R_inv
viewmat[:3, 3:4] = T_inv

3.3 在CUDA 中 对3D Gaussian 进行投影:

  1. 投影的椭圆近似成一个圆, 保存圆的半径 和中心点的xyz 坐标即可
    当一个 Gaussian 投影成一个圆之后,那么他的半径 和 椭圆的 标准差是密切相关的:
    在这里插入图片描述
    给定二维高斯分布的协方差矩阵 Σ \Sigma Σ ,通过计算该矩阵的特征值并取其平方根,我们可以得到分布的“半径”,协方差的特征值可以认为是 椭圆的两个方向的半径。求解 下面的方程即可:
    在这里插入图片描述
    可以进一步的展开:
    ( a − λ ) ( c − λ ) − b 2 = 0 (a-\lambda)(c-\lambda)-b^2=0 (aλ)(cλ)b2=0

圆的圆心,可以直接通过 3D Gaussian 的中心点 Center 投影得到。

  1. 计算覆盖的像素
    快速的方法,将图像分成 16*16 的tile; 计算每一个 Tile 和圆的 相交区域。
    在这里插入图片描述
    3.对每一个高斯按照深度顺序进行排序
    一个Tile 可能会有很多个 Gaussian 进行覆盖, CUDA 程序会根据每一个 Tile 会对其覆盖的 Gaussian 进行深度排序
    在这里插入图片描述

  2. 计算每一个像素的颜色
    每一个 Tile 对应着 一个block; 而每一个Pixel 对应着一个 thread。
    计算 每一个像素到2D 投影圆的距离,并且依据 高斯分布 求解出 opacity 的大小。


网站公告

今日签到

点亮在社区的每一天
去签到