ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

3DGS动态干扰物过滤:Per-View Gaussian Predictions原理与实现

3DGS动态干扰物过滤:Per-View Gaussian Predictions原理与实现 静态场景训练出的 3D Gaussian Splatting3DGS在高保真渲染和实时速度之间取得很好的平衡但一旦场景里出现行人、车辆、飞鸟等动态干扰物重建结果就会出现透明拖影和漂浮噪点。Per-View Gaussian Predictions 是近期针对该问题的一种方法思路通过前馈网络从每个视角单独预测高斯参数再利用多视角一致性在推理阶段完成无需额外训练的干扰物过滤。它不要求为每个新场景标注动态物体也不要求在测试时重新优化一个分割网络而是把“过滤”变成预测结果之间的一致性判断。这篇文章会从3DGS为何怕动态物说起拆解 Per-View Gaussian Predictions 的原理、过滤流程、复现环境、参数设计和排查路径最后给出一套可以直接用于实验验证的工程思路。1. 先理解3DGS为什么对动态干扰物如此敏感1.1 3DGS建立在静态世界假设之上3D Gaussian Splatting 不是把场景表示成网格或体素而是表示成一组可微的 3D 高斯。每个高斯通常包含中心位置、协方差矩阵、颜色和不透明度渲染时把每个高斯投影到图像平面再按视点到高斯中心的深度排序通过 alpha blending 叠加颜色。这个流程听起来很直接但它隐含了一个关键假设同一个空间位置在所有输入视角里保持静止。换句话说三维空间中的某一个点不管从哪个相机看、不管在哪一帧出现它的颜色、位置和遮挡关系都应该一致。真实采集场景很难满足这个假设。行人会移动车辆会穿过画面树叶会晃动甚至光影也会变化。于是优化过程会为了压低重建损失把本该是“动态临时物体”的部分也建模成一组半透明高斯结果就是渲染画面出现拖影和漂浮物。可以把 3DGS 的优化理解成一个不断“解释”所有照片的过程。它不知道照片里的某个物体以后还会不会出现只知道当前这组像素需要被解释。动态物体在多个视角里出现在不同位置3DGS 无法用少数几个高斯同时满足这些位置所以只能用大量低不透明度的高斯分布在运动轨迹上形成一种“概率式”的视觉近似。1.2 动态干扰物带来的典型伪影动态干扰物对 3DGS 重建质量的影响可以分成几类实际项目里经常同时出现。伪影类型表现原因透明拖影行人和车辆周围出现半透明残影动态物在不同视角位置不同无法用一个实心高斯覆盖漂浮噪点渲染画面随机出现小块亮点或暗点优化产生大量低不透明度高斯分布在运动轨迹附近背景撕裂静止墙面或地面出现错位、模糊为兼顾前景和背景背景高斯被拉伸或偏移渲染排序错误局部物体边缘闪烁、发黑动态物导致深度排序不稳定远→近绘制顺序被破坏其中渲染排序问题经常被忽略。3DGS 的高斯数量和场景复杂度直接影响排序成本硬件光栅化在做远→近混合时依赖稳定的深度。动态干扰物会让同一块区域在不同视角下深度突变排序结果也随之抖动最终渲染出的边缘质量很差。1.3 直接使用语义分割并不能根治看到动态物伪影很多人第一反应是先用语义分割把行人、车辆抠掉再送入 3DGS 重建。这个方案可行但工程代价和边界问题很多。首先语义分割模型需要在目标场景或相似场景上有足够鲁棒性。一个只在公开道路数据集上训练过的分割模型遇到施工围挡、反射倒影、强光光斑或穿着特殊服装的行人时可能漏检或误检。其次分割掩码的边缘往往不准确如果把边缘像素直接抠掉重建的静态背景会出现硬边界如果保留太多动态物边缘又会重新进入优化。再者大量场景需要实时过滤比如机器人实时建图或线上三维重建而每帧跑一次重型分割网络会明显增加延迟。因此真正值得做的不是“识别出动态物体类别”而是“判断某个高斯是否在所有视角中保持一致”。Per-View Gaussian Predictions 正是从一致性角度出发绕开了依赖语义类别的问题。2. Per-View Gaussian Predictions 的核心思路2.1 从全局联合优化到逐视图预测传统 3DGS 的构建方式是全局优化先通过 SfM 得到相机位姿和初始点云再把所有图像放在一起用自适应高斯优化逐步调整高斯数量和参数。这个过程中每个高斯对全部视角负责。Per-View Gaussian Predictions 改变了粒度。它用一个前馈网络对每个视角的图像独立预测高斯参数而不是把所有图像一次性联合优化。前馈的含义是一次前向计算直接得到结果不需要测试时迭代。网络学习的目标是从单张图像估计“在当前视角下场景可以被哪些高斯表示”。这种视角级预测天然适合干扰物过滤。动态物在视角 A 和视角 B 中即使看起来相似它的真实三维位置也不同。逐视图预测后把两组预测结果反投影到同一个世界坐标系里动态物对应的高斯会出现明显的位置冲突而静态背景高斯会彼此吻合。冲突本身就是过滤依据。2.2 前馈网络预测哪些高斯参数为了完成跨视角一致性判断网络预测的参数需要覆盖渲染和几何验证两方面的需求。常见情况下每个视角的预测结果会包含下面几类信息。参数含义在过滤中的作用位置高斯中心在相机坐标系或世界坐标系中的坐标反投影后用于判断两个视角是否指向同一个空间点协方差高斯形状、尺寸、朝向决定反投影时的覆盖范围和匹配窗口颜色高斯对应的视觉外观用于颜色一致性验证排除错误匹配不透明度高斯对渲染结果的贡献程度用于剔除低置信度或接近透明的干扰项实际网络不一定直接输出完整协方差矩阵也可能输出深度图、特征向量或隐式参数再由后处理模块转换成渲染器需要的格式。这里的关键是最终得到的表示必须支持“从不同视角反投影到同一个三维位置”否则一致性过滤无法进行。2.3 “训练自由”不是“完全不用训练”标题里的 Training-Free 在中文里容易造成误解。它并不是说整个过程不需要任何训练而是说在过滤干扰物的阶段不需要针对当前场景训练分割网络或二分类器。网络本身依然是预训练得到的而且一个在前馈预测任务上表现优秀的模型往往需要在大量多视图场景上学习过。这样设计的好处在于可迁移性。采集新场景时不需要为新场景标注任何动态物体掩码也不需要在新场景上微调网络。只要预训练模型能对单张图像输出合理的高斯参数就可以通过跨视角一致性过滤掉大多数动态干扰物。这种“训练自由”更准确地说是“过滤阶段零训练”或“测试时不需要额外训练”。3. 不需要额外训练基于预测一致性过滤干扰物3.1 多视角一致性为什么能区分背景和干扰物三维重建的本质是从多张图像中恢复一致的三维结构。静态背景中的同一个物理点不管从哪个视角观察经过相机位姿变换后都应该落在同一个世界坐标附近颜色也不应该突变。动态物则不满足这一点因为相机拍摄时间不同物体已经移动到了不同位置。所以一致性判断可以跳出语义类别只比较几何和外观。位置误差小、颜色误差小、深度变化连续的高斯更可能是静态背景位置误差大、颜色误差大或深度跳变明显的高斯更可能是动态干扰物或被遮挡区域。这个逻辑不依赖具体物体类别因此也能处理分割模型从未见过的干扰物。需要注意的是一致性判断的有效性高度依赖相机位姿。如果位姿本身不准确所有高斯的反投影都会出现误差后续过滤阈值会失真。因此在工程中先校正位姿或使用更稳定的 SfM 结果比盲目调整过滤参数更重要。3.2 过滤流程的四个环节一个完整但不过度复杂的干扰物过滤流程可以拆成四个环节输入一组多视角图像和对应相机位姿。用前馈网络对每个视角独立预测高斯参数。将相邻视角的预测结果反投影到世界坐标系建立对应关系。计算位置、颜色、深度或不透明度的一致性分数剔除分数低于阈值的高斯。这里“相邻视角”并不一定是时间相邻帧而是指与该视角有足够共视区域的相机。如果两个视角没有重叠投影后的对应关系没有意义比较出来的分数也不可靠。3.3 伪代码示例下面是一段用于说明思路的伪代码不是某个具体仓库的官方实现。它展示了过滤主流程中最重要的几步。def filter_gaussians(images, poses, K, predictor, threshold0.5): world_candidates [] per_view_preds [] for image, pose in zip(images, poses): pred predictor(image) pred[pose] pose per_view_preds.append(pred) for idx, pred in enumerate(per_view_preds): # 把当前视角预测的中心转换到世界坐标系 centers_world to_world(pred[center], pred[pose]) for neighbor_idx in neighbor_view_indices(idx, len(images)): neighbor per_view_preds[neighbor_idx] # 将世界系中心投影到邻居视角 projected project(centers_world, neighbor[pose], K) # 从邻居视角参数图采样对应位置的高斯参数 observed_center sample(neighbor[center], projected) observed_color sample(neighbor[color], projected) pos_error distance( centers_world, to_world(observed_center, neighbor[pose]), ) color_error color_distance(pred[color], observed_color) score consistency_score(pos_error, color_error, pred[opacity]) if score threshold: world_candidates.append(assemble_gaussian(pred)) break return world_candidates这段代码没有处理很多工程细节比如遮挡、误差传播、最近邻搜索加速和 GPU 内存复用但它把最重要的逻辑表达清楚了先把每个视角的预测结果统一到一个坐标系再通过跨视角采样计算误差最后用阈值决定保留还是剔除。实际项目中建议把反投影和采样操作放入自定义 CUDA 算子否则 Python 循环会非常慢。3.4 计算效率与数值稳定性在真实场景里每帧图像可能预测出数十万甚至上百万个候选高斯Python 层面的循环完全不可接受。常见的优化手段包括把一致性计算改成张量操作或融合 kernel。用固定分辨率参数图而非逐点独立高斯减少数量。使用稀疏特征匹配先找出高响应区域再只对这些区域做反投影。在一致性打分前先做粗略深度滤波去掉深度极端值。对长时间序列使用滑动窗口只对窗口内的高斯做一致性验证。数值稳定方面要避免在相机位姿矩阵无法求逆时直接反投影也避免在图像边界外采样。项目里常见的做法是给采样函数一个掩码当投影坐标超出图像范围时直接视为不一致。4. 复现时需要准备的环境与依赖4.1 推荐环境组合下面是一套常见的深度学习三维重建环境组合适合作为实验起点。实际版本要以官方仓库的 requirements 为准因为 GPU 驱动、CUDA 版本和 PyTorch 版本之间的兼容关系变化很快。软件常见版本说明Ubuntu20.04 / 22.04主流 3D 重建生态支持较好Python3.8 - 3.10过新版本容易遇到 torch 扩展编译问题PyTorch1.13 / 2.0需要与 CUDA 匹配CUDA11.7 / 11.8视 PyTorch 构建版本而定diff-gaussian-rasterization项目源码版本3DGS 原始渲染器gsplat0.1.x 或更高轻量可微高斯光栅化库COLMAP3.8用于相机位姿估计和稀疏点云4.2 建议的目录结构复现实验时一个清晰的目录结构能减少很多路径配置问题。下面是一个最小可用的组织方式。project ├── configs # 实验配置文件 │ └── pvgf.yaml ├── data # 原始图像和位姿文件 │ ├── images │ └── poses ├── gaussian_predictor # 前馈预测网络定义 │ ├── model.py │ └── head.py ├── filters # 一致性过滤逻辑 │ ├── consistency.py │ └── project.py ├── renderer # 高斯渲染封装 │ └── render.py ├── scripts │ └── run_predict.py └── logs # 日志和输出结果这种结构把预测、过滤、渲染三部分拆开方便单独验证哪一步出了问题。日志目录一定要从一开始就保留输出否则后期调试回归时会很难定位。4.3 安装命令示例当官方仓库没有给出完整安装脚本时可以按下面步骤先搭好基础环境。conda create -n pvgf python3.10 -y conda activate pvgf pip install torch2.0.1 torchvision --index-url https://download.pytorch.org/whl/cu118 pip install gsplat opencv-python tqdm einops pyyaml如果官方仓库依赖自定义 CUDA 算子还需要把它们加入环境变量或者通过 setup.py 编译。具体编译命令通常写在 README 中不要跳过这一步否则运行时会直接报找不到共享库。安装完成后用下面命令验证基础组件可用。nvidia-smi python -c import torch; print(torch.cuda.is_available()) python -c import gsplat; print(gsplat.__version__)如果torch.cuda.is_available()返回 False不要急着跑模型先检查 PyTorch、CUDA 驱动和 GPU 驱动三者的匹配关系。这个问题排在所有代码问题之前必须先解决。5. 关键参数与实验设计5.1 输入视图数对过滤效果的影响输入视图数量直接决定一致性验证的信息量。视图越少越难判断某个高斯是否真的静止视图越多显存占用和计算延迟越高。视图数优点风险2计算快显存占用低遮挡和误匹配无法消除4 - 6过滤效果较稳适合做对比实验需要保证视角间有足够重叠8 以上可以处理复杂遮挡显存压力大预测和投影耗时长实际采集数据时尽量让每个静态区域至少被三个视角覆盖。如果某个区域只出现在一个视角里它既可能是背景也可能是无法验证的干扰物最终结果会偏向保留或偏向剔除这两种情况都不理想。5.2 预测分辨率与高斯数量前馈网络输出的分辨率会影响高斯数量估计。高分辨率下边缘细节更清晰但参数图包含更多像素后续一致性计算的量级也会成倍增长。低分辨率下计算量下降但小物体会被合并干扰物掩膜不够精细。常见做法是把输入图像缩放到 512 到 1024 之间的分辨率然后让预测器输出同分辨率参数图。实际项目里先用 512 分辨率跑通流程再逐步提高观察 PSNR 和显存变化。不要一开始就在原始 4K 图上做全部步骤排错成本太高。5.3 一致性阈值的标定一致性阈值是最敏感的参数。阈值过小动态物残留阈值过大静态背景也被删除。由于不同模型的位置误差和颜色误差量纲不同不存在一个万能阈值。建议在少量验证帧上做一个阈值扫描实验。统计每个阈值下保留高斯数量和渲染图像的 PSNR找到“背景完整度”和“干扰物去除率”之间的平衡点。通常可以从 0.3 到 0.7 的范围内搜索步长 0.05 左右。阈值干扰物去除效果背景保留效果偏小动态物残留明显背景完整适中大多数动态物被剔除背景轻微损失偏大动态物几乎全部被剔除静态部分出现空洞5.4 消融实验与评价指标如果把该方法作为研读或复现对象建议至少做三组消融实验去掉位置一致性、去掉颜色一致性、去掉不透明度加权。这样可以看出每个信号对最终效果的贡献。评价指标建议使用PSNR衡量整体渲染质量。SSIM衡量结构相似性。LPIPS衡量感知一致性。干扰物区域 IoU如果验证集有标注可以专门评估动态物过滤效果。还可以统计单位时间处理的视角数评估工程可落地性。很多论文方法在静态数据集上指标很好但放到动态采集流程中往往因为速度太慢而无法使用。6. 从实验结果看方法的边界6.1 典型收益当输入视角有足够重叠、相机位姿准确、前馈预测器质量稳定时基于逐视图一致性过滤的方案会产生几个明显效果。渲染画面中的行人、车辆拖影会被抑制背景边缘更干净。不需要为每个新场景训练分割模型处理一个新采集场景时只要跑一次前向推理和一致性过滤即可流程比“训练一个局部分割网络 重建”更快。由于过滤逻辑基于几何和外观一致性它对未见过的动态物体类别也有一定泛化能力不会被固定语义类别限制住。6.2 容易失效的场景任何一致性方法都有边界。最常见的是长时间遮挡场景一个干扰物在连续多帧中一直挡住同一块背景周围所有视角都只能看到它静态背景反而没有足够证据此时一致性打分无法判断它是静态还是动态。另一种容易失效的情况是相机与目标同步运动。比如无人机跟随行人拍摄时行人在图像中的位置始终固定网络预测结果在不同视角中看起来“一致”于是算法会把动态目标当成背景保留。这种情况下需要额外引入时序光流或特征轨迹才能打破同步运动造成的伪一致。还有一类场景是重复纹理或反射表面。透明玻璃、水面、金属反光会让位置误差和颜色误差相互矛盾一致性打分不稳定。简单阈值容易把这些区域全部剔除导致重建背景残缺。6.3 从学习环境到生产环境的差距学习环境通常使用已经整理好的数据集、标准位姿、无遮挡视角。生产环境更复杂。维度学习环境生产环境相机位姿通常精确可能存在漂移或标定误差动态物体比例可控可能长时间占据大部分画面计算资源充足显存、CPU、功耗受限实时要求不高可能要求在线处理失败回退可以重新运行离线实验需要自动告警和回退机制在生产环境落地时不能只保留过滤后结果。建议保留原始图像和过滤参数当某个区域被过度删除时可以快速回到原始高斯基元重新渲染避免一次不可逆操作破坏整个模型。7. 常见问题与排查路径7.1 显存不足导致 OOM现象运行到逐视图预测或多视角投影时进程报 CUDA out of memory。可能原因输入视图数太多、图像分辨率太高、前馈预测器推理时保留了梯度、批量处理了过大的张量。检查方式nvidia-smi查看显存占用峰值是否接近显存上限并确认代码中是否缺少torch.no_grad()。处理建议在过滤推理阶段显式关闭梯度with torch.no_grad(): pred predictor(image)如果仍然 OOM降低输入分辨率或逐张图像计算后再放入反投影模块不要一次性把所有视角的参数图攒成超大 batch。7.2 渲染结果出现大量漂浮点现象过滤后渲染画面布满小而亮的噪点类似手机夜景照片的噪点。可能原因前馈预测器在无纹理或过曝区域输出了大量低置信度高斯一致性过滤只检测到了位置冲突却没有过滤不透明度很低的高斯反投影时对深度极小或极大的点没有做范围限制。检查方式把每一帧预测的深度图、不透明度图可视化观察噪点区域对应的参数值是否异常。统计保留高斯的中心坐标分布看是否存在离相机极近或极远的孤立点。处理建议增加高斯数量下限和深度范围限制对不透明度小于阈值的预测直接丢弃不再参与一致性比较。渲染前还可以用中值滤波清理孤立高斯。7.3 阈值太严格导致背景残缺现象静止墙面或地面被删掉渲染后出现黑色空洞或半透明空洞。可能原因一致性打分过严相机位姿误差被当成动态误差背景本身存在自遮挡或反射导致不同视角颜色差异大。检查方式关闭阈值过滤只保留预测器输出的原始高斯观察背景是否完整。如果完整说明问题出在过滤阶段再看一致性分数的分布找到静态背景的分数范围。处理建议不要只用一个全局阈值。可以按深度区间设置不同阈值或加入颜色一致性的软权重。对于反射和玻璃区域建议单独关闭位置一致性只使用颜色一致性。7.4 渲染器维度不匹配或黑屏现象过滤后生成的高斯列表传入渲染器出现张量维度错误或全黑画面。可能原因预测器输出的是二维参数图渲染器需要的是三维高斯列表坐标系不一致参数值范围没有归一化到渲染器预期范围。检查方式打印预测结果的 shape、dtype、最小值、最大值。再从预测器到渲染器逐层检查确认坐标转换发生在哪个模块、转换矩阵是否正确。处理建议统一使用一个坐标系定义。通常在预测阶段输出相机坐标系参数在过滤阶段转换到世界坐标系在渲染阶段再转换回相机坐标系。任何一个环节忘记转换结果都会异常。7.5 系统性排查顺序如果问题定位不到可以按下面的顺序排查。每次只改一个变量并把中间结果保存下来。输入图像是否有损坏、重复、乱序。相机位姿是否与图像一一对应。前馈网络是否成功加载预训练权重。预测参数是否在当前视角内合理。反投影使用的内参和畸变系数是否正确。一致性打分是否存在 NaN 或无穷大。阈值是否经过验证集标定。最终渲染器是否使用了正确的高斯列表。这个顺序的核心思路是从数据输入往输出方向走不要一开始就怀疑网络结构。大多数训练自由过滤流程的问题都出在坐标变换和阈值设定上。8. 最佳实践与扩展方向8.1 数据采集阶段就要为过滤留好余地过滤效果受采集方式影响很大。拍摄时尽量绕场景多转一圈让每个静态区域至少被多个视角覆盖避免在一个位置长时间停留拍摄同一个动态物体如果有可能让相机在时间维度上存在明显位姿变化增加动态物位置差异这样一致性分数会更有区分度。位姿质量是过滤效果的上限。如果使用 COLMAP先看稀疏点云是否发散如果使用标定相机定期检查内参是否漂移。采集结束后先做一次位姿质量检查再进入预测和过滤。8.2 把过滤方法接入现有3DGS流程实际项目中不一定要推翻现有重建管线可以分阶段接入。在初始化阶段先对输入图像做逐视图预测和一致性过滤用过滤后的候选高斯初始化场景再进入常规 3DGS 优化。这样能避免动态物在优化初期进入场景。在渲染阶段如果场景里还残留部分动态高斯可以在每次渲染前对高斯列表做快速一致性检查用过滤后的列表绘制。这种方法对在线场景比较友好但需要把过滤逻辑做成 GPU 算子否则会拖慢渲染帧率。在在线重建场景中建议使用滑动窗口。每个窗口保留最近 N 个视角的预测结果只对窗口内一致性低的高斯做剔除窗口滑过之后再重新评估。这样比每帧全量过滤更快也能处理物体逐渐离开画面的情况。8.3 值得继续尝试的方向逐视图预测与一致性过滤的组合还有很多扩展空间。可以在一致性打分阶段把二值剔除改成软权重。保留所有高斯但对一致性低的高斯降低不透明度让渲染结果在“过滤掉”和“保留住”之间连续过渡减少硬边界。可以引入时序信息。把连续多帧的光流或点轨迹作为一致性打分的额外特征专门解决相机与目标同步运动的场景。这个方向对自动驾驶和城市级三维重建尤其有价值。可以针对不同渲染器做适配。有的项目使用原始 diff-gaussian-rasterization有的项目使用 gsplat还有项目使用自研光栅化器。前馈预测的输出格式需要为不同渲染器增加转换层让过滤结果能直接进入各自的高斯列表。对于新手来说最值得做的练习不是直接复现完整模型而是在已经训练好的 3DGS 模型上加入一个简单的一致性后处理。先可视化每个高斯的跨视角误差分布理解哪些高斯是动态物哪些是背景再逐步替换成前馈预测方式。这样能更快建立起对“一致性为什么有用、阈值为什么难调”的直觉。实际项目中最值得记住的一点是训练自由不等于零成本它的上限由前馈预测器的泛化能力和相机位姿精度共同决定。在复现或使用这类方法时先把输入视图数量、分辨率和一致性阈值调到一个能在显存限制下稳定运行的配置再把动态干扰物过滤当成一个置信度估计问题而不是简单的删除问题。后续无论是做在线重建还是大规模城市三维重建都可以从逐视图预测与多视角一致性的组合中继续延伸。
返回列表