语义运动图SMG:单目动态3D高斯重建新思路

语义运动图SMG:单目动态3D高斯重建新思路 过去两年一直在跟三维重建和 AIGC 方向打交道最直观的感受是静态场景重建已经做到相当成熟大家的注意力几乎都转向了“怎么让场景真的动起来”。从静态 NeRF 到动态 NeRF再到 3D Gaussian Splatting实时渲染的门槛被打下来之后“动态”就成了下一个厮杀激烈的战场。但真正从单目视频里做动态 Gaussian 重建时你会发现问题比想象中难得多。单目输入意味着相机只从一个视角观察场景运动信息本身就不完整再加上动态物体经常遮挡、形变、超出画面纯靠像素误差去反推运动很容易把物体的真实位移学习成“几何扭曲”或者“半透明拖影”。最近在读相关文献时看到一篇工作题目是SMG: Semantic Motion Graph for Monocular Dynamic Gaussian Splatting。它把“语义”和“运动图”引入动态高斯建模目标是解决单目动态场景里长期重建不稳定、运动表达不清晰的问题。这篇内容我不打算做逐字逐句的论文翻译而是结合动态 Gaussian 场景重建的技术演进把 SMG 的核心设计思路、它解决了什么问题以及这类方法如果要落地复现需要注意哪些工程细节做一个完整梳理。1. 动态场景重建背景3D Gaussian 是怎么“动起来”的1.1 静态 Gaussian Splatting 先解决“怎么表示场景”在理解动态 Gaussian 之前还是得先回顾一下静态 3D Gaussian Splatting 的基本思路。3D Gaussian Splatting后面简称 3DGS把三维场景表示为一堆带空间位置、旋转、尺度、颜色和透明度的三维高斯原语。渲染的时候这些高斯原语被投影到二维图像平面再根据深度排序用类似 alpha blending 的方式合成最终像素颜色。相比 NeRF 那种用 MLP 隐式表达场景的方式3DGS 最大的优势是显式表达每个高斯的位置和属性可以直接编辑可微光栅化渲染训练和推理速度都远快于逐点采样的 NeRF重建质量高在静态场景中能保留较好的细节。正因为“显式”和“可编辑”当场景从静态变成动态时大家很自然会想能不能让每个高斯在不同时刻有不同的位置和属性1.2 动态高斯的两类建模路线从目前已公开的技术路线看动态 3D Gaussian 大体可以分成两类思路。一类是先重建一个静态模板再学一组随时间变化的变形场或者叫 deformation field。每个高斯点先计算自己的位置在某个时间戳下的偏移量然后把偏移后的高斯再做光栅化渲染。这种方案的优势是能复用静态场景重建的成熟框架比较稳定。另一类做法是把时间维度显式建模到神经网络或体素网格里直接把动态场景表示成一个整体。比如在一些 4D 表示方法中输入空间坐标和时间输出对应的密度和颜色或者直接输出每个 3D 高斯的运动轨迹。SMG 更偏向第一类但又没有停留在“纯逐点变形”思路上它希望给变形过程加一个更高层次的结构约束让大量高斯原语在运动时不是各自为战而是带着语义分组和局部运动关联一起动。1.3 语义信息在动态重建中的价值如果只靠光度一致性损失训练动态高斯模型对运动的理解往往是不够的。一个典型的失败场景是人物的手臂在单目视角里被身体挡住模型看不到手臂后续帧的真实位置为了降低渲染误差它就可能把那一片区域的高斯拉成奇怪的形状硬凑出类似颜色的像素。引入语义信息后模型可以先知道“哪些像素属于同一个人哪些像素属于同一个运动部位”从而把运动约束从逐像素升到逐物体、逐部位。这也是 SMG 这类方法的设计动机所在。可以把这里的语义理解为一种“运动分组先验”。它不要求模型理解物体到底是什么而是告诉模型哪些区域应该整体移动、哪些区域之间存在相对运动关系。语义分割、实例分割乃至视频分割模型都可以提供这种先验。2. 单目动态高斯面临的三大关键难点2.1 观测信息严重不足单目视频和 RGB-D 或同步多视角视频最大的区别在于每个时刻只有一张图像。三维场景本身存在尺度歧义深度信息只能从运动视差、物体尺寸等间接线索中估计。在多视角动态重建里某个点被遮挡了还可以靠另一个视角看到它但单目场景一旦某块区域被遮挡该区域在后续若干帧里就可能彻底“消失”。对动态 Gaussian 来说这意味着相关高斯的运动轨迹没有任何梯度信号约束训练很容易在这些区域出现随机漂移。这也是为什么许多方法在单目数据集上跑出来的结果静态背景还过得去一动起来就到处是漂浮噪点、半透明碎片。2.2 遮挡区域的运动不可见动态场景几乎天然伴随遮挡。人走路时手臂摆动会遮挡躯干车辆经过时会短暂遮挡后方建筑这类遮挡在单目视角中是不可回避的。一般做法是让模型对不可见区域做“想象”利用时间上下文推断被遮挡物体的合理运动。但神经网络如果缺少结构化先验这种“想象”经常是以牺牲几何质量换来的重建出的物体会出现形变塌陷。语义运动图可以帮助缓解这个问题当一个物体被部分遮挡时图上可见部位的节点可以约束隐藏节点的运动估计因为图结构本身表达了不同部位之间的关联关系。2.3 运动与几何形变难以解耦更本质的困难是渲染一张图像像素时同时取决于场景的几何位置和每个点的外观属性。如果模型把几何推错了完全可以靠修改局部高斯的颜色、透明度来弥补渲染误差这在单视角监督下经常无法被有效发现。这种“几何与运动错误互相补偿”的问题让动态高斯训练很容易陷入局部最优物体明明没有移动模型却用颜色变化去拟合或者物体真的移动了模型却靠改变高斯形状去强行匹配。要让训练真正学到正确的运动就必须给网络额外的约束。这些约束可以来自时序平滑项、刚性约束、运动一致性也可以来自 SMG 所代表的语义分组约束。SMG 的关键突破在于它把场景中的运动表达组织成语义运动图让每个语义节点包含一组高斯原语并且用边显式表达不同节点之间的运动一致性或相对运动关系。这样运动不再是一个无结构的向量场而是一组可解释、可约束的语义运动单元。3. SMG语义运动图设计思路拆解3.1 什么是语义运动图结合目前公开讨论中对该模型的描述可以把语义运动图理解为一个轻量的图结构。它的核心不再是单个像素或单个高斯点而是整组语义一致的高斯原语。这里可以想象一种简化版流程先用视频分割模型或语义分割模型将每个视频帧中的物体按语义类别区分开然后在三维空间中把这些语义区域对应的高斯点组织成节点用“边”连接在运动上存在关联的节点。图结构带来的优势是显式地建模了物体局部的运动连通性。例如人的两条腿之间不是完全独立的它们在走路时存在循环交替的相位关系一辆车的车门和车身在开合过程中又存在铰链式的相对旋转。这些运动关系很难直接靠 MLP 隐式学出来但用图结构表达就比较自然。需要注意的一点是语义运动图和骨架运动学不完全一样。骨架模型通常依赖明确的人体关节定义而语义运动图的适用范围更宽不一定要有生物体关节它可以表达一般物体的部件关系和区域运动。3.2 SMG 如何约束动态高斯运动从技术上看SMG 引入了一种分层运动建模策略。底层依然是每个高斯个体的形变轨迹高层则多了一个语义运动图用来指导底层运动。比如某个高斯点属于“人物右前臂”这个语义节点。在估计该点的位移时SMG 会让它参考所属节点的整体运动参数而不是一开始就输出一个完全自由的独立位移。这样带来的好处有几点如果一个区域的大部分高斯运动方向和幅度一致那么个别点即使因为遮挡缺少监督也能被节点级运动约束拉回正确轨迹语义节点之间存在显式的相对运动关系模型比较容易学习长时间的周期性运动减少累积漂移图结构让运动结果具有可解释性我们可以反查某个物体在某个时间段内是怎么移动的。从工程实现角度理解SMG 大概率会在渲染流程中加入一个运动估计分支。这个分支负责从已经分割好的语义区域中预测每个节点在下一时间戳的变换然后每个 Gaussian 的运动量等于自身变形量加上所属语义节点的变换贡献。这个过程需要用可微方式实现才能把渲染误差反传回去。3.3 语义引导损失与训练整体流程动态高斯训练的核心损失仍然是渲染图像和真实图像之间的差异常见的是 L1 颜色损失加 SSIM 感知损失。SMG 在此基础上会额外加入运动图和分割相关的正则化约束。一种典型的约束是属于同一语义节点的高斯点应当具有尽量一致的运动行为。如果训练过程中某个点和其他同组点的位移方向差异太大就会受到额外惩罚。这种损失本质上是把语义分组当成一种运动平滑先验。另一个可能涉及的损失项是图连接的时序一致性在相邻时间戳之间同一根边对应的相对运动变化应当是平滑的不能出现剧烈跳变。这和视频插值、动态场景重建里常用的时序平滑约束类似但被限制在语义运动图上执行计算量更小约束也更精准。从宏观训练流程来看SMG 这种框架通常包含三部分基础静态 3DGS 建模用于给每个动态高斯提供初始位置和外观运动图构建和语义掩码关联将二维语义掩码提升到三维高斯分组联合优化外观、几何、语义运动图同时优化最终得到一个可渲染动态帧并对运动可解释的模型。4. 工程化理解一个可运行的流程骨架思路这部分不是论文官方实现而是帮助理解 SMG 技术思路的流程骨架。实际复现时不同数据集的预处理方式、分割模型选择、Gaussian 初始化策略都会直接影响精度需要根据具体实验调整。4.1 前置依赖与配置建议从工程环境来看建议准备以下依赖# 建议使用 Linux NVIDIA GPU conda create -n smg python3.10 -y conda activate smg pip install torch torchvision pip install pillow numpy tqdm opencv-python pip install gaussian-splatting # 或使用对应源码中的 diff-gaussian-rasterization版本方面需要根据具体项目环境调整。比如 PyTorch 版本需要和 CUDA 版本匹配diff-gaussian-rasterization 在部分 PyTorch 版本下需要从源码编译这些属于老生常谈的坑。配置阶段建议额外准备一个预训练的视频分割模型例如基于 SAM2 或 Mask2Former 的模型用来生成语义掩码一个有效的 COLMAP 或类似工具标定结果单目视频输入时相机位姿是必备的显存不低于 16GB 的 GPU动态场景加上语义图会明显增加显存占用。4.2 从分割掩码构建运动图的代码示意要理解语义运动图的工程实现可以先从二维分割掩码构建区域邻接图开始。import numpy as np from collections import defaultdict def build_semantic_motion_graph(masks): 输入masks形状为 [H, W]每个像素值为对应语义实例的编号。 输出节点列表和边列表的近似表示。 说明这是一个流程演示不是 SMG 官方实现。 h, w masks.shape node_ids np.unique(masks) node_ids node_ids[node_ids 0] node_set set(int(x) for x in node_ids) edge_set set() # 四邻域判断如果相邻像素属于不同语义区域则认为它们之间存在潜在运动关联 for y in range(h - 1): for x in range(w - 1): a int(masks[y, x]) b int(masks[y, x 1]) c int(masks[y 1, x]) if a ! b: if a in node_set and b in node_set: edge_set.add((min(a, b), max(a, b))) if a ! c: if a in node_set and c in node_set: edge_set.add((min(a, c), max(a, c))) nodes sorted(node_set) edges sorted(edge_set) return nodes, edges这段代码本质上只完成了二维掩码的区域邻接聚类。要把它真正接到 Gaussian 模型上还需要把二维区域映射到三维高斯点。比较直接的做法是将每个高斯点投影回图像坐标然后根据它落在哪个语义掩码区域内决定该高斯点属于哪个语义节点。投影关系需要随着高斯点的位置变化动态更新因此训练过程中不能只算一次而要周期性重新对齐。4.3 与高斯变形网络结合的损失示意下面给一个更靠近训练流程的伪代码片段用于展示语义运动约束如何参与损失计算。def compute_loss(rendered_rgb, gt_rgb, offsets, node_offsets, group_ids): rendered_rgb: 渲染图像 gt_rgb: 真实图像 offsets: 每个高斯独立的位移量 node_offsets: 每个语义节点的位移量 group_ids: 每个高斯所属的语义节点编号 l1_loss torch.abs(rendered_rgb - gt_rgb).mean() # 语义分组一致性约束 # 对于同一个语义组内的高斯其独立位移量应该和节点级位移量保持接近 semantic_loss 0.0 unique_nodes torch.unique(group_ids) for node in unique_nodes: mask group_ids node if mask.sum() 0: mean_offset offsets[mask].mean(dim0) node_offset node_offsets[node] semantic_loss torch.abs(mean_offset - node_offset).mean() return l1_loss 0.01 * semantic_loss从损失设计可以看出语义运动约束并不是直接替代颜色损失而是作为附加正则项告诉模型“同组高斯在运动上应当保持一致”。实际论文还会处理相对运动、时序平滑、节点间旋转约束等更多细节上面的代码只是帮助建立直觉。4.4 典型目录结构在工程复现时推荐参考以下目录结构组织代码和数据smg_project/ ├── configs/ │ └── smg_dynamic.yaml ├── data/ │ ├── train/ │ │ └── rgb/ │ ├── masks/ │ └── poses/ ├── segment/ │ └── build_graph.py ├── gaussian/ │ ├── model.py │ ├── motion_mlp.py │ └── render.py ├── losses/ │ └── semantic_loss.py └── train.py这个结构和普通 Gaussian Splatting 项目的区别在于多了一个segment/目录专门负责语义分割、掩码处理和运动图构建motion_mlp.py则负责预测语义节点层面的运动参数。5. 实验与效果上看什么5.1 想验证的核心指标对于动态场景重建方法常见量化指标包括 PSNR、SSIM、LPIPS这些指标衡量渲染图像和真实图片的接近程度。单目动态场景文章通常会选一组包含大幅度运动、遮挡明显、循环运动的数据集来评估。但只看平均指标是不够的。SMG 这类方法真正想提升的点在于长期重建稳定性在较长视频序列中是否出现高斯漂移、闪烁、形状塌陷遮挡情况下的运动保持度某个物体被其他物体挡住后重新出现时是否还能维持原来的外观和运动轨迹运动边界清晰度运动物体和静态背景之间是否出现粘连、透明模糊可编辑性和泛化性运动图结构能否迁移到新的时序或新的驱动信号上。所以阅读论文实验结果时建议同时关注定量表格和可视化对比视频。有时候 PSNR 提升并不明显但时域稳定性、视觉新颖视角合成的质量差异会更突出。5.2 重点可视化对比动态 Gaussian 方法的可视化一般分两类。一类是时间维度上的新视图合成让同一个时间戳从不同角度渲染另一类是空间确定下的时间推移即固定视角渲染整段视频。对单目方法而言更值得关注的是第二类结果模型能否忠实还原视频中的运动。如果渲染视频中物体的运动幅度明显小于真实视频或者出现位置抖动这通常说明运动场建模还不够好。在看可视化结果时可以重点关注以下区域人体运动的四肢末端比如手、脚这些部位容易出现运动模糊或跟踪丢失物体接触地面的位置运动物体和静态场景接触部分容易出现滑步或穿透快速运动造成的运动模糊区域模型往往倾向于把模糊当作半透明高斯群。具体的数值表现和数据集细节需要以论文原文为准不同实验条件下不能直接横向比较。6. 复现踩坑经验与工程建议6.1 数据与掩码准备如果你准备基于 SMG 的思路自行实验第一个最容易出问题的环节是语义掩码的质量。SAM2 等视频分割模型在常见物体上效果很好但在严重遮挡、快速运动、运动模糊时会输出不稳定的掩码掩码时有时无会直接导致后续运动图构建失败。一种缓解方式是做时序掩码传播和平滑。先用分割模型预测若干关键帧掩码然后通过光流或特征匹配把掩码传播到中间帧再做时序中值滤波减少掩码闪烁。另一个建议是控制场景复杂度。初期实验尽量选择单个动态物体加静态背景的场景比如一个摆动的玩具、一段行走的人体视频。多动态物体之间互相遮挡会大幅增加语义运动图构建和优化的难度。6.2 训练设置与收敛误区动态 Gaussian 训练非常容易陷入几种假性收敛背景被模型改得模糊用来补偿前景运动前景物体变成透明淡影只保留静态背景模型把所有帧都渲染成同一姿态颜色损失不高但运动完全错误。这些问题的根源往往是运动网络学习率设置过高导致运动估计在初期不能保持稳定。合理的做法是采用分阶段训练先冻结运动分支只优化静态高斯外观把场景基础建好再逐步放开运动网络学习让模型在良好初始条件下学习位移。监控训练曲线时除了看总损失还要单独记录前景区域和背景区域的损失。如果背景损失下降正常而前景损失长期停滞大概率是运动建模出了问题。6.3 显存与渲染加速动态 Gaussian 相比静态版本多了一个运动 MLP 或运动图模块显存占用会明显上升。如果遇到显存不足可以考虑以下方案降低训练图像分辨率或者在训练初期使用随机裁剪控制 Gaussian 数量上限删除透明度过低的高斯原语减少每个 batch 采样的时间戳数量不要一次把所有帧都参与梯度回传使用混合精度训练。推荐在配置中增加自动保存和恢复机制。动态训练通常以小时为单位计算一旦中期 loss 发散能恢复到最近一次稳定 checkpoint 会节省大量时间。常用问题整理成表格如下问题现象常见原因解决思路前景物体透明化运动分支学习率过高或静态初始化不充分先冻结运动网络训练静态模型再逐步解冻语义掩码闪烁导致运动图断裂视频分割模型不稳定用光流做掩码传播并增加时序平滑动态物体出现拖影运动幅度超过初始搜索范围对运动网络输出加幅度约束或增加时间采样密度训练显存不足高斯数量和采样帧数过多降低分辨率、删除低透明度高斯、减少批量采样渲染结果中物体位置漂移相机位姿误差较大先检查 COLMAP 位姿重投影误差再进行训练6.4 语义运动图的定位最后想强调一点工程认知语义运动图不是替代场景流或变形场而是在它们之上增加约束。它的作用更像是给一组自由度过高的高斯点做“降维”让运动产生过程更受控、更可解释。因此在实际落地时不一定非要严格复现论文的每一个细节也可以把这个思想加入自己的动态 Gaussian 流程中。比如先用视频分割模型抽几层语义区域然后让区域内的高斯共享一个额外的运动正则项往往就能显著改善单目场景下运动漂移问题。7. 总结与下一步SMG 在单目动态 Gaussian Splatting 方向上提供了一种更有结构感的运动建模思路。它把场景从“一堆会移动的高斯点”提升为“一组有语义关联的运动区域”让模型在面对遮挡、快速运动和长序列时多了可依赖的时空约束。如果对动态场景重建感兴趣下一步可以继续看这几个方向4D Gaussian Splatting 表示了解如何把时间直接纳入高斯参数人体动态 Gaussian 重建看语义先验更强时的做法比如引入骨骼节点视频分割基础模型语义运动图对掩码质量非常敏感掌握 SAM2 这类工具的接口和微调方式会有直接帮助场景流估计与运动场建模了解无监督光学/场景流在动态 Gaussian 中的配合方式。从工程角度建议先跑通一个普通的静态 3DGS再往里面加入变形场最后再尝试语义运动图约束。因为动态重建的 bug 排查难度远高于静态重建直接一上来复现完整方法出现问题时会很难定位究竟是语义分割的问题、运动网络的问题还是高斯初始化的锅。希望这篇内容能帮你梳理清楚 SMG 的方法动机和参考价值。如果有已经在跑动态 Gaussian 的朋友欢迎在评论区聊聊你们遇到的运动漂移问题以及语义分组对它是否真的有改善。