三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

从COLMAP稀疏点云到3D高斯:手把手教你用Gaussian Splatting源码初始化第一个场景

从COLMAP稀疏点云到3D高斯:手把手教你用Gaussian Splatting源码初始化第一个场景

从COLMAP稀疏点云到3D高斯:Gaussian Splatting场景初始化全流程解析

在计算机视觉领域,3D场景重建技术正经历着从传统点云到神经渲染的范式转变。Gaussian Splatting作为2023年提出的创新性方法,通过将场景表示为可优化的3D高斯分布集合,实现了实时渲染与高质量重建的完美平衡。本文将深入剖析Gaussian Splatting源码中create_from_pcd方法的实现细节,揭示从COLMAP稀疏点云到可优化高斯模型的完整转换逻辑。

1. 技术背景与核心概念

Gaussian Splatting的核心思想是将3D场景建模为数千个可学习的高斯椭球体集合。每个高斯分布由以下参数定义:

  • 位置(xyz):3D空间坐标
  • 旋转(rotation):四元数表示的朝向
  • 缩放(scaling):各轴向的尺寸
  • 不透明度(opacity):可见程度
  • 外观(appearance):球谐系数表示的颜色和材质

与传统NeRF方法相比,这种显式表示具有三大优势:

  1. 渲染效率:通过基于瓦片的栅格化实现实时渲染
  2. 可优化性:所有参数可通过梯度下降进行调整
  3. 动态适应性:支持高斯分布的分裂与克隆

在初始化阶段,系统需要从稀疏点云(如COLMAP输出的points3D.bin)生成这些高斯参数的合理初始值。这正是create_from_pcd方法的核心任务。

2. 数据准备与预处理

2.1 COLMAP输出解析

COLMAP作为经典的运动恢复结构(SfM)工具,其典型输出包含三个关键文件:

文件名称内容描述数据结构
cameras.bin相机内参和外参每相机一行
images.bin图像位姿与特征点关联每图像一行
points3D.bin三角化得到的稀疏点云每点包含xyz和rgb

scene.dataset_readers.readColmapSceneInfo函数负责解析这些数据,其中points3D.bin的读取结果将转换为BasicPointCloud对象:

class BasicPointCloud(NamedTuple): points: np.array # (N,3) float32 colors: np.array # (N,3) float32 [0,1] normals: np.array # (N,3) float32 (未使用)

2.2 空间尺度归一化

在初始化前,系统会计算场景的空间尺度因子spatial_lr_scale

def getNerfppNorm(cam_info): cam_centers = np.array([camera_center(cam) for cam in cam_info]) avg_center = np.mean(cam_centers, axis=0) max_dist = np.max(np.linalg.norm(cam_centers - avg_center, axis=1)) return 1.1 * max_dist

这个值代表相机中心到场景最远距离的1.1倍,用于后续调整位置参数的学习率,确保不同尺度场景下的训练稳定性。

3. 核心参数初始化策略

3.1 位置与颜色初始化

create_from_pcd方法首先处理最基础的位置和颜色参数:

fused_point_cloud = torch.tensor(pcd.points).float().cuda() # (N,3) fused_color = RGB2SH(torch.tensor(pcd.colors).float().cuda()) # (N,3)

其中RGB2SH转换公式为:

SH = (RGB - 0.5) / 0.28209479177387814

这里的0.282094...是球谐函数中Y₀⁰的值(1/2√π),将RGB颜色转换到球谐函数的直流分量。

3.2 尺度参数初始化

尺度参数的初始化是整个过程最精妙的部分,采用近似KNN算法计算每个点的局部密度:

dist2 = torch.clamp_min(distCUDA2(pcd.points), 0.0000001) scales = torch.log(torch.sqrt(dist2))[...,None].repeat(1, 3)

distCUDA2函数的实现逻辑:

  1. 使用Morton编码将3D点映射到1D空间
  2. 对编码排序后,计算每个点与最近3个邻居的平均距离
  3. 返回距离平方作为局部密度估计

最终尺度参数取对数后的值,因为后续会通过指数函数激活:

scale = exp(scaling_param)

这种设计确保尺度始终为正数,且初始大小与点云局部密度相适应。

3.3 旋转与不透明度初始化

旋转参数初始化为单位四元数:

rots = torch.zeros((N, 4), device="cuda") rots[:, 0] = 1 # 实部为1,虚部为0

不透明度参数初始化为0.1(经过逆sigmoid变换):

opacities = inverse_sigmoid(0.1 * torch.ones((N, 1)))

其中inverse_sigmoid(x) = ln(x/(1-x)),确保优化过程中不透明度始终在(0,1)范围内。

4. 球谐系数与优化准备

4.1 球谐系数布局

对于最大球谐阶数sh_degree=3,各系数内存布局如下:

系数类型数量存储形状说明
直流分量3(N,3,1)RGB各通道的Y₀⁰
高阶分量45(N,3,15)l=1到3的各阶系数

初始化时仅使用直流分量,高阶项设为零:

features = torch.zeros((N, 3, (max_sh_degree+1)**2)) features[:, :3, 0] = fused_color

4.2 参数优化设置

所有参数被封装为可训练的张量:

self._xyz = nn.Parameter(fused_point_cloud) self._features_dc = nn.Parameter(features[...,0:1].transpose(1,2)) self._features_rest = nn.Parameter(features[...,1:].transpose(1,2)) self._scaling = nn.Parameter(scales) self._rotation = nn.Parameter(rots) self._opacity = nn.Parameter(opacities)

训练时各参数采用不同的学习率策略:

参数类型初始学习率衰减策略相对重要性
位置0.00016×spatial_lr_scale指数衰减最高
颜色直流0.0025固定
颜色高阶0.000125固定
不透明度0.05固定
缩放0.005固定
旋转0.001固定

5. 工程实现细节与优化

5.1 内存布局优化

为提高内存访问效率,球谐系数采用特殊的存储顺序:

# 保存为PLY文件时的属性顺序 attributes = ['f_dc_0', 'f_dc_1', 'f_dc_2'] + \ [f'f_rest_{i}' for i in range(45)]

这种布局确保同一高斯的所有参数连续存储,提升缓存命中率。

5.2 梯度累积与自适应控制

训练过程中会监控各高斯的梯度变化:

self.xyz_gradient_accum = torch.zeros((N,1), device="cuda") self.denom = torch.zeros((N,1), device="cuda") # 步数计数器

基于梯度信息实现两种自适应操作:

  1. 克隆:对梯度大但尺度小的高斯
  2. 分裂:对梯度大且尺度大的高斯

分裂策略特别值得关注:

new_xyz = R @ (samples * scale/N) + parent_xyz # 在父高斯局部坐标系采样 new_scaling = parent_scale / (0.8*N) # 尺度收缩

其中N=2表示分裂成两个子高斯,0.8是经验收缩因子。

6. 性能优化技巧

6.1 CUDA内核优化

关键计算均通过定制CUDA内核实现:

  1. KNN近似:基于Morton编码的空间划分
  2. 球谐计算:预计算基函数值
  3. 栅格化:并行瓦片渲染

6.2 参数量化

保存模型时对参数进行适当量化:

dtype_full = [(attr, 'f4') for attr in attributes] # 32位浮点

实际应用中可进一步采用16位浮点存储,减少模型体积。

6.3 场景自适应策略

根据场景复杂度动态调整:

  1. 初始点云密度:COLMAP参数影响初始高斯数量
  2. 球谐阶数:简单场景可用sh_degree=1
  3. 裁剪阈值:基于相机距离剔除不可见高斯

7. 实战建议与常见问题

7.1 数据准备最佳实践

  • 图像采集:建议80-200张重叠率>60%的照片
  • COLMAP参数
    colmap feature_extractor --SiftExtraction.max_image_size 4000 colmap exhaustive_matcher --SiftMatching.guided_matching true

7.2 初始化问题排查

问题现象可能原因解决方案
点云过稀疏特征匹配不足增加输入图像数量/质量
颜色偏差RGB范围错误确保颜色值在[0,1]范围内
尺度异常空间归一化失败检查相机参数单位一致性

7.3 高级调参技巧

  • 初始不透明度:复杂场景可提高到0.2
  • 尺度约束:添加L2正则防止过度膨胀
  • 渐进式训练:先低阶球谐,后引入高阶项

在真实项目中使用这些技术时,建议从官方提供的"garden"场景开始,逐步调整参数。一个常见的误区是过度追求初始点云密度,实际上Gaussian Splatting的密度控制算法能在训练过程中自动优化分布。

← 返回列表