EmbodMocap: In-the-Wild 4D Human-Scene Reconstruction for Embodied Agents
Paper: arXiv:2602.23205 Code: WenjiaWang0312/EmbodMocap Code reference:
main@fff6c252(2026-03-10)
1. Motivation (研究动机)
Embodied AI 需要的不只是“人怎么动”的轨迹,而是“人在什么 3D 场景里、以什么物理约束和物体发生交互”的数据。互联网视频虽然规模大,但单目视频天然缺少 metric scale、相机轨迹、深度、遮挡后的身体约束和可复用的场景 mesh;传统 motion capture / LiDAR / 多相机 studio 又昂贵、固定、难以搬到真实室内外环境里大规模采集。因此,现有数据要么有高质量人体运动但场景弱,要么有场景但人体和交互弱,要么依赖受控环境,难以支撑 embodied agents 学习真实 human-scene behavior。
这篇论文要解决的具体问题是:用尽可能低成本、可移动的消费级设备,在 in-the-wild 场景中同时恢复 metric-scale 3D scene mesh、dual-view camera trajectory、world-space SMPL human motion,并把它们放到同一个统一世界坐标系中。作者选择“两台移动 iPhone + RGB-D + IMU + 几何优化”的设计,目标不是做一个新的人体网络,而是建立一个可搬到任意真实环境的数据采集与重建系统。
Figure 1 解读:图中把输入和产物的边界说得很清楚:输入只需要 RGB-D frames、camera parameters 和两台 iPhone 视角;不需要 mocap suit、static cameras、LiDAR sensor 或硬件同步。输出同时覆盖 scene mesh 与 human motion,并可直接服务 monocular reconstruction、physics-based character animation 和 real-world humanoid motion control。这个设定的价值在于把“真实人在真实场景中的长期行为”变成可对齐到 3D 世界坐标的训练资料。
为什么值得做:一旦可以低成本采集 scene-conditioned human motion,就能把 embodied learning 从 studio 数据扩展到日常室内外环境;下游可以训练单目 human-scene reconstruction 模型,验证 motion 是否物理可执行,甚至把视频中的人类动作迁移到 humanoid robot 上。论文的核心卖点是降低数据采集门槛,而不是单点提升某个 benchmark。
2. Idea (核心思想)
核心 insight:先用单 iPhone 建立 metric、gravity-aligned 的静态场景世界坐标,再把双 iPhone 动态人体序列注册到这个世界坐标中,最后用双视角几何约束优化人体 motion。这样把最难的 4D human-scene reconstruction 拆成 scene world frame、sequence calibration、world-space human optimization 三个可控问题。
关键创新可以概括为三点:第一,用 SpectacularAI / COLMAP / TSDF fusion 得到低成本但有 metric scale 的 scene reference;第二,用 dual-view RGB-D 和 VGGT / Chamfer / bundle adjustment 等约束把两条移动相机轨迹对齐到同一场景;第三,用 triangulated 3D keypoints 和 world-space SMPLify 把人体姿态从 camera space 拉到 scene space。与 EMDB、RICH、Nymeria 等依赖 EM sensors、scanners、多设备或高成本 setup 的数据采集不同,EmbodMocap 追求的是“portable + outdoor-capable + scene mesh + dynamic annotation”的组合。
与单目人体重建方法(如 GVHMR / VIMO)相比,根本差异不是 backbone,而是可观测性:单目方法在深度方向和 scene alignment 上存在歧义;EmbodMocap 用两个移动视角建立 pixel / point correspondence,并通过场景 mesh 与相机轨迹共同约束人体根平移,因此能把 motion 放到真实 scene coordinate system 中。
3. Method (方法)
3.1 Overall framework:四阶段 4D human-scene reconstruction
Figure 2 解读:整体 pipeline 从左到右分成四个阶段:Stage I 用单 iPhone RGB-D/IMU 建 scene mesh 和 COLMAP sparse reference;Stage II 用两台 iPhone 采集同一场景内的人体 motion,并提取 YOLO / ViTPose / SAM2 / depth / VIMO 先验;Stage III 把两个动态相机轨迹和 scene world frame 对齐;Stage IV 固定 camera 与 scene,优化 world-space SMPL motion。图中的关键不是每个 off-the-shelf module 本身,而是它们被组织成一个逐步消除坐标系歧义的系统。
直觉上,EmbodMocap 可行的原因是把“运动人体 + 移动相机 + 静态场景”中耦合最强的变量分阶段解开:先让静态 scene 决定 metric world frame,再让双视角相机轨迹在这个 frame 里校准,最后只优化人体参数。若没有 Stage I,所有序列缺少统一尺度与重力方向;若没有 Stage III,两个 iPhone 的相机坐标无法稳定合并;若没有 Stage IV,VIMO 等 camera-space SMPL 先验无法变成场景中可交互的 motion。
3.2 Stage I:Scene Reconstruction
输入是一段静态场景 RGB-D video 和 IMU。SpectacularAI SDK 根据 accumulated camera translation 自动选 keyframes,并输出相机内参和 Z-up、metric-scale 世界坐标下的相机姿态 。随后系统用 depth refinement(论文写 PromptDA;released code 已替换为 LingbotDepth,见下方差异说明)修正 iPhone LiDAR depth,把 depth map unproject 成点云,再用 TSDF fusion 得到全局 mesh 。论文中 depth truncation 使用 indoor 3.5m、outdoor 5m;released code 的 embod_mocap/config.yaml 使用 indoor 4.0m、outdoor 5.0m。
Stage I 还会从相同 keyframes 提取 SIFT features,并用固定相机参数跑 COLMAP,得到保留 metric scale 的 sparse structure database。这个 database 后续用于把动态人体序列中的两个 iPhone 轨迹注册回场景。
3.3 Stage II:Sequence Processing
Stage II 在同一个场景里用两台 iPhone 录制同步 RGB-D videos。每个 view 有自己的 camera coordinate system;SAI 为每帧图像 输出 。人体相关信息由多个现成模型提取:YOLO 做 person detection,ViTPose 做 2D keypoints,SAM2 做 person masks,depth model 做深度 refinement,VIMO 输出 camera-space SMPL parameters。
Figure 3 解读:该图展示的是作者的低成本同步技巧:用 laser pointer cue 在两个视频流里制造一个可检测事件,通过 laser dot 消失的 frame index 做 frame-level synchronization。它不是硬件同步,但足以把双视角 RGB-D、mask、keypoints 和 SMPL priors 裁切到同一时间轴上,从而进入后续几何校准。
Figure 4 解读:补充图展示 camera-space 中的 rendered SMPL 与 depth images,说明 Stage II 保存的不只是 RGB 图像,还包含后续优化会用到的 segmentation、depth、camera trajectory 与 human parameters。这些中间资产也是 released code 中 standard 模式与 fast 模式的主要区别:standard 保留更多 RGBD/mask 资产,fast 更偏向 mesh + motion。
3.4 Stage III:Sequence Calibration
Stage III 要解决三个坐标系不一致的问题:scene reconstruction 的 world frame,以及两台 iPhone 各自的 SAI trajectory frame。首先,系统用 Stage I 的 sparse COLMAP model 和已知 intrinsics ,在去除 human mask 后的 background-only SIFT features 上注册每个动态序列,得到 COLMAP camera poses 。然后求解 Procrustes-style offset,把 SAI translations 对齐到 COLMAP translations: 由于 SAI 与 COLMAP 都是 gravity-aligned,论文把 约束为绕 轴旋转。之后进一步优化 per-view global offsets 和 : 校准目标由 tracking、Chamfer 与 bundle adjustment 组成: $ \mathcal{L}{\mathrm{calib}} = \lambda{\mathrm{track}} \mathcal{L}_{\mathrm{track}}
- \sum_{v} \lambda_{\mathrm{ch}} d_{\mathrm{Chamfer}}
- \sum_{v} \lambda_{\mathrm{ba}} \mathcal{L}{\mathrm{ba},v}.
\boldsymbol{Q}{v,t}^{(i)} = d_{v,t}^{(i)} \boldsymbol{R}{v,t}^{\top \mathrm{ali}} \boldsymbol{K}v^{-1}
\begin{bmatrix}
\boldsymbol{q}{v,t}^{(i)} \ 1
\end{bmatrix} + \boldsymbol{R}{v,t}^{\top \mathrm{ali}} \boldsymbol{T}{v,t}^{\mathrm{ali}},
\mathcal{L}{\mathrm{track}} = \frac{1}{\sum_{v,t} |\mathcal{Q}{v,t}|}
\sum_t \sum_i \tilde{w}{t}^{(i)}
\left| \boldsymbol{Q}{1,t}^{(i)} - \boldsymbol{Q}{2,t}^{(i)} \right|2^2,
\quad \tilde{w}{t}^{(i)} = \min(w_{1,t}^{(i)}, w_{2,t}^{(i)}).
\boldsymbol{\mathcal{P}}_v\boldsymbol{\mathcal{P}}g
\begin{aligned}
d{\mathrm{Chamfer}}(\boldsymbol{\mathcal{P}}_v, \boldsymbol{\mathcal{P}}_g)
&= \frac{1}{|\boldsymbol{\mathcal{P}}v|} \sum{\boldsymbol{p}_v \in \boldsymbol{\mathcal{P}}v}
\min{\boldsymbol{p}_g \in \boldsymbol{\mathcal{P}}_g} \left|\boldsymbol{p}_v - \boldsymbol{p}_g\right|_2^2 \
&\quad + \frac{1}{|\boldsymbol{\mathcal{P}}g|} \sum{\boldsymbol{p}_g \in \boldsymbol{\mathcal{P}}g}
\min{\boldsymbol{p}_v \in \boldsymbol{\mathcal{P}}_v} \left|\boldsymbol{p}_g - \boldsymbol{p}_v\right|_2^2.
\end{aligned}
$
released code 中,
optim_human_cam.py对应的实现还显式加入了 point-to-point loss:human_pc_loss * 2 + chamfer_loss1 + chamfer_loss2 + ba_loss_v1 + ba_loss_v2 + p2p_v1_loss + p2p_v2_loss。其中 Chamfer 权重为0.1,VGGT human point cloud MSE 乘10,P2P loss 乘1e5 / num_points,默认max_iters=100、lr=1e-3,并在config.yaml中启用chamfer=true, vggt_track=true, dba=true, p2p=true, z_rot_only=true。
3.5 Stage IV:Motion Optimization / World-Space SMPLify
Stage IV 固定相机与场景,只优化人体。先用双视角 2D keypoints triangulate 出 world-space 3D keypoints :
其中 。代码中 optim_motion.py 调用 triangulate_sequence(...),随后用 confidence threshold:2D confidence 大于 0.6 才保留,3D confidence 用两个 view confidence 的乘积且大于 0.36。
World-Space SMPLify 从 VIMO 的 initial shape 和 body pose 出发,联合优化 shape、global/body pose 和 root translation:
released code 中该过程是两阶段 optimization:第一阶段只优化 global_orient 和 transl,kp3d_loss_weight=1.0、kp3d_smooth_loss_weight=1.0、num_iters=200、lr=1e-2;第二阶段优化 global_orient, betas, body_pose, transl,kp3d_loss_weight=2.0、两视角 reproj_loss_weight=2.0、smooth 类权重为 1.0、prior regularization 为 10.0、motion/kp3d acceleration 权重为 5、num_iters=300、lr=1e-2。config.yaml 默认开启 optim_kp3d=true, use_prior=true, reproj=true, use_kp3d=true, smooth=true, pcscale=4。
Figure 5 解读:补充图展示如何在软件中找到 contact marker 和对应 keyframe index。它对 downstream RL/robot control 很重要,因为 ground / furniture contact 的时序如果错位,sim policy 会学到 floating、interpenetration 或错误支撑点。
3.6 论文公式与 released code 实现差异
- PromptDA vs LingbotDepth:论文 Stage I / II 写的是 PromptDA;released
README.md明确说明 open-source release 将 PromptDA 替换为 LingbotDepth,checkpoint 路径在embod_mocap/config_paths.py中是lingbot_depth_vitl14.pt。 - Depth truncation:论文写 indoor 3.5m、outdoor 5m;released
embod_mocap/config.yaml的 scene / human unprojection 默认 indoordepth_trunc=4.0、outdoordepth_trunc=5.0。 - Calibration objective:论文主公式列出 tracking + Chamfer + bundle adjustment;released
optim_human_cam.py还默认加入p2ploss,并通过config.yaml打开。 - Fast profile:
config_fast.yaml不是论文结果配置,而是 release 中为了更快处理 mesh + motion 的工程配置,例如 scenevoxel_size=0.02、COLMAP images200、VGGT samples100、keyframes30。
3.7 Pseudocode from released implementation
def build_scene_mesh(scene_folder, cfg, paths):
# run_stages.py steps 1-3 + processor/unproj_scene.py
key_frame_dist = cfg.steps.sai.in_door.key_frame_dist # or out_door = 0.15
run_spectacular_ai(scene_folder, key_frame_dist)
rgb, depth, K, RT = load_sai_keyframes(scene_folder)
depth = refine_depth_with_lingbot_depth(depth, paths.lingbotdepth_ckpt)
depth = depth.clip(max=cfg.steps.recon_scene.in_door.depth_trunc)
tsdf = ScalableTSDFVolume(
voxel_length=cfg.steps.recon_scene.in_door.voxel_size,
sdf_trunc=cfg.steps.recon_scene.in_door.sdf_trunc,
)
for image_t, depth_t, pose_t in zip(rgb, depth, RT):
tsdf.integrate(image_t, depth_t, K, pose_t)
mesh_raw = tsdf.extract_triangle_mesh()
mesh_raw = remove_outliers_and_small_components(mesh_raw)
sift_features = extract_background_sift(scene_folder)
colmap_db = rebuild_colmap_with_fixed_cameras(sift_features, K, RT)
return mesh_raw, colmap_dbdef process_dual_view_sequence(seq_path, cfg, paths):
# run_stages.py steps 4-11
frames_v1, frames_v2 = decode_raw_videos(seq_path, down_scale=cfg.steps.get_frames.down_scale)
cameras_v1, cameras_v2 = smooth_sai_cameras(seq_path)
frames_v1, frames_v2 = slice_by_laser_pointer_cue(frames_v1, frames_v2)
smpl_v1 = run_vimo(frames_v1, checkpoint=paths.vimo_ckpt)
smpl_v2 = run_vimo(frames_v2, checkpoint=paths.vimo_ckpt)
masks_v1 = run_sam2_or_lang_sam(frames_v1, paths.sam2_ckpt)
masks_v2 = run_sam2_or_lang_sam(frames_v2, paths.sam2_ckpt)
kpts_v1 = run_vitpose(frames_v1, paths.pose_model_ckpt)
kpts_v2 = run_vitpose(frames_v2, paths.pose_model_ckpt)
tracks = run_vggt_tracking(
frames_v1, frames_v2,
num_sample=cfg.steps.vggt_track.vggt_track_samples,
)
return cameras_v1, cameras_v2, smpl_v1, smpl_v2, masks_v1, masks_v2, kpts_v1, kpts_v2, tracksdef calibrate_human_cameras(scene_points, view1, view2, cfg):
# processor/optim_human_cam.py::optim_cam
R1_off, T1_off = init_colmap_alignment(view1.cameras_sai, view1.cameras_colmap)
R2_off, T2_off = init_colmap_alignment(view2.cameras_sai, view2.cameras_colmap)
if cfg.steps.optim_human_cam.z_rot_only:
R1_off, R2_off = z_axis_rotation_params(R1_off), z_axis_rotation_params(R2_off)
params = [R1_off, T1_off, R2_off, T2_off]
opt = torch.optim.Adam(params, lr=1e-3)
for _ in range(100):
cam1 = apply_offset(view1.cameras_sai, R1_off, T1_off)
cam2 = apply_offset(view2.cameras_sai, R2_off, T2_off)
loss = 0.0
if cfg.steps.optim_human_cam.vggt_track:
pc1 = backproject_vggt_tracks(view1.depth, cam1, view1.tracks)
pc2 = backproject_vggt_tracks(view2.depth, cam2, view2.tracks)
loss = loss + 2.0 * (10.0 * F.mse_loss(pc1, pc2))
if cfg.steps.optim_human_cam.chamfer:
loss = loss + 0.1 * chamfer_distance(unproject_scene(view1, cam1), scene_points)
loss = loss + 0.1 * chamfer_distance(unproject_scene(view2, cam2), scene_points)
if cfg.steps.optim_human_cam.dba:
loss = loss + dense_bundle_adjustment_loss(view1, cam1)
loss = loss + dense_bundle_adjustment_loss(view2, cam2)
if cfg.steps.optim_human_cam.p2p:
loss = loss + point_to_point_colmap_depth_loss(view1, cam1)
loss = loss + point_to_point_colmap_depth_loss(view2, cam2)
opt.zero_grad()
loss.backward()
opt.step()
return export_aligned_cameras(cam1, cam2)def optimize_world_space_smpl(seq_path, cfg):
# processor/optim_motion.py
K1, R1, T1, K2, R2, T2 = load_calibrated_dual_view_cameras(seq_path)
kp2d_1, kp2d_2 = load_vitpose_keypoints(seq_path)
smpl_init = load_vimo_smpl_params(seq_path)
kp3d = triangulate_sequence(K1, K2, R1, T1, R2, T2, kp2d_1[..., :2], kp2d_2[..., :2])
conf1 = (kp2d_1[..., 2:3] > 0.6) * kp2d_1[..., 2:3]
conf2 = (kp2d_2[..., 2:3] > 0.6) * kp2d_2[..., 2:3]
if cfg.steps.optim_motion.optim_kp3d:
kp3d = kp3d_smoothing(kp3d, reprojection_inputs=(K1, R1, T1, K2, R2, T2), num_iters=100, lr=1e-2)
stages = [
dict(active_params=["global_orient", "transl"], kp3d=1.0, kp3d_smooth=1.0, num_iters=200),
dict(active_params=["global_orient", "betas", "body_pose", "transl"],
kp3d=2.0, reproj=2.0, smooth=1.0, prior=10.0, accel=5.0, num_iters=300),
]
smpl_params = smpl_init.to_world_space()
for stage in stages:
opt = torch.optim.Adam(select_params(smpl_params, stage["active_params"]), lr=1e-2)
for _ in range(stage["num_iters"]):
joints, verts = smpl_forward(smpl_params)
loss = weighted_kp3d_loss(joints, kp3d, conf1 * conf2, stage)
loss = loss + dual_view_reprojection_loss(joints, kp2d_1, kp2d_2, K1, R1, T1, K2, R2, T2, stage)
loss = loss + smoothness_and_prior_losses(smpl_params, joints, verts, stage)
opt.zero_grad(); loss.backward(); opt.step()
return save_npz(seq_path / "optim_params.npz", smpl_params)3.8 Code-to-paper mapping
Code reference:
main@fff6c252(2026-03-10) — pseudocode and mapping based on this commit
| Paper Concept | Source File | Key Class/Function |
|---|---|---|
| Unified stage runner / 16 processing steps | embod_mocap/run_stages.py | full_steps, step commands for SAI, scene reconstruction, sequence processing, calibration, motion optimization |
| Standard / fast pipeline config | embod_mocap/config.yaml, embod_mocap/config_fast.yaml | steps.sai, steps.recon_scene, steps.vggt_track, steps.optim_human_cam, steps.optim_motion |
| Checkpoint / model paths | embod_mocap/config_paths.py | PATHS.vimo_ckpt, PATHS.sam2_ckpt, PATHS.lingbotdepth_ckpt, PATHS.vggt_ckpt |
| Stage I TSDF scene reconstruction | embod_mocap/processor/unproj_scene.py | tsdf_clean, unproj_depth, vggt_depth_predict |
| Stage II masks/depth/keyframes | embod_mocap/processor/process_depth_mask.py | generate_masks, filter_points2d_with_masks, keyframe selection flags |
| Stage II / III VGGT correspondences | embod_mocap/processor/vggt_track.py | vggt_track_pair, visualize_vggt_tracks |
| Stage III camera calibration | embod_mocap/processor/optim_human_cam.py | optim_cam, apply_rigid_to_RT_torch, dense_ba_loss_fn use |
| Stage IV world-space SMPLify | embod_mocap/processor/optim_motion.py | triangulate_sequence, kp3d_smoothing, smplify_optimization |
| Contact alignment for downstream embodied tasks | embod_mocap/processor/align_contact.py | contact-marker based alignment invoked as step 16 |
| VIMO/HMR model used for SMPL prior | embod_mocap/human/backbone/vimo.py, embod_mocap/human/backbone/hmr2.py | HMR_VIMO, HMR2 |
4. Experimental Setup (实验设置)
4.1 Dataset scale and comparison
论文主数据集在补充材料中写明:收集自 23 个真实场景,每个场景有 high-precision mesh,共 104 sequences,约 200,000 video frames;每帧包含 depth maps、segmentation masks、camera trajectories 和 human parameters(bounding boxes、2D keypoints、SMPL parameters)。camera trajectory length 分布约 4m 到 30m+,human trajectory length 约 5m 到 30m+;indoor scene mesh 面积约 20–90 ,outdoor 可到 200 ;大多数 sequence 长度 30–60 秒。
Figure 6 解读:该图展示 collected dataset 的 3D demo,强调 EmbodMocap 不是只输出人体骨架,而是把人体 motion、camera trajectory 和 scene mesh 同时放在同一 3D 场景中。对 embodied agents 来说,这比孤立 motion clip 更有用,因为场景几何和 contact surface 是策略学习的一部分。
Figure 7a–7d 解读:四个统计图分别对应 camera trajectory length、human trajectory length、scene mesh area 和 sequence length。它们共同说明数据覆盖了从短距离室内活动到 30m+ 长轨迹、以及较大 outdoor scenes 的范围;这也是作者声称数据适合 long-term scene-aware motion tracking 的依据。
Table 1 中 EmbodMocap 与已有数据集的关键对比:
| Dataset | Publication | Main devices | Total cost | Mesh | Dynamic annotation | Outdoor |
|---|---|---|---|---|---|---|
| PROX | ICCV 2019 | Structure Sensor + Kinect-One | 2K | ✓ | ✗ | ✗ |
| RICH | CVPR 2022 | Leica RTC360 + 6–8 static cams + 1 dynamic cam | 20K+ | ✓ | ✓ | ✓ |
| EgoBody | ECCV 2022 | 5 Kinect + Hololens2 | 9K | ✓ | ✓ | ✗ |
| SLOPER4D | CVPR 2023 | Noitom PN+NUC11 + Ouster-os1 LiDAR + DJI-Action2+TLS | 20K | ✓ | ✓ | ✓ |
| EMDB | ICCV 2023 | EM sensors + 1 dynamic cam | 15K | ✗ | ✓ | ✓ |
| Nymeria | ECCV 2024 | Xsens + Aria Wristband + 2 Aria | 60K+ | ✗ | ✓ | ✓ |
| EmbodMocap | CVPR 2026 | 1 scanner-like iPhone scene pass + 2 dynamic iPhones | 1K | ✓ | ✓ | ✓ |
4.2 Evaluation tasks and baselines
论文用三类 downstream tasks 验证数据价值:
- Monocular human-scene reconstruction:baseline 使用 做 SLAM / camera 和 local point maps,VIMO 做 metric-scale human motion reconstruction;在 EMDB subset 2 上用 WA-MPJPE、W-MPJPE 和 RTE 评估。
- Physics-based character animation:在 simulator 中训练 Follow、Climb、Sit、Lie、Prone、Support 等 human-object interaction skills;对比 Optical Mocap、Ours 1X / 2X / Full,以及 Monocular(GVHMR predicted motions)。指标是 Success Rate、Contact Error 和 APD。
- Scene-aware motion tracking / humanoid robot control:用 reconstructed motions 和 scene/contact 信息训练 tracking policies,真实 humanoid 部分使用 High Torque Hi robot,21 joint DoF;基于 BeyondMimic 风格 sim-to-real RL 与 domain randomization。
Figure 8 解读:图中四个长时序例子覆盖 walking、sitting、lying、stair climbing、touching 等日常场景动作。右侧 zoom-in 强调 reference data 中可能有 floating 或 interpenetration,而 scene-aware tracking policy 能利用 scene/contact 约束修正这些物理不合理现象。
4.3 Training / processing configuration
论文未详细说明所有 downstream training 的 GPU type/count、RL learning rate、总训练步数等超参数;released repo 也主要发布 EmbodMocap processing pipeline,而不是完整 downstream RL / fine-tuning launch scripts。因此这里区分“论文未披露”和“released code 可验证配置”。
released embod_mocap/config.yaml 的 standard pipeline 配置包括:
sai: indoorkey_frame_dist=0.1,outdoor0.15。recon_scene: indoor/outdoordepth_trunc=4.0/5.0,sdf_trunc=0.1,voxel_size=0.01,vggt_refine=false。get_frames:down_scale=2;slice_views:jpeg_quality=5,remove_raw_images=true。colmap_human_cam:colmap_num=400,min_valid_ratio=0.2;generate_keyframes:min_tracks=10,num_keyframes=50,min_keyframes=20。process_depth_mask:need_all_depth_mask=true,depth_refine_max_size=960,depth_refine_chunk_size=4,lang_sam_chunk_size=5。vggt_track:vggt_track_samples=200;unproj_human: indoor stride30、outdoor stride40。optim_human_cam:chamfer=true, vggt_track=true, dba=true, p2p=true, z_rot_only=true。optim_motion:pcscale=4, post_smooth=false, optim_kp3d=true, use_prior=true, reproj=true, use_kp3d=true, smooth=true。
released embod_mocap/processor/config_vimo.yaml 中 VIMO/HMR-style config 写有:DEVICE=cuda、NUM_WORKERS=15、IMG_RES=256、SEQ_LEN=16、BATCH_SIZE=24、LR=1e-5、LR2=3e-5、WARMUP_STEPS=3000、MAX_STEP=250000、OPT=AdamW、WD=0.01。但这看起来是 model config 文件;论文的 EMDB fine-tuning 只文字说明了对 加 LoRA、VIMO frozen encoder + decoder MSE,没有给出完整硬件与训练 schedule。
5. Experimental Results (实验结果)
5.1 Monocular human-scene reconstruction on EMDB
Figure 9 解读:该图展示 fine-tuned reconstruction pipeline 在 EMDB 上的 qualitative result,重点是大规模真实视频中人体和场景的空间对齐。它补充了 Table 4 的数值结果:EmbodMocap 数据可以提升 VIMO / 的 world-coordinate prediction,而不只是做一个 capture demo。
EMDB subset 2 quantitative results:
| Fine-tuned | Fine-tuned VIMO | WA-MPJPE ↓ | W-MPJPE ↓ | RTE ↓ |
|---|---|---|---|---|
| ✗ | ✗ | 83.56 | 229.04 | 1.78 |
| ✗ | ✓ | 82.89 | 222.93 | 1.73 |
| ✓ | ✓ | 82.21 | 220.65 | 1.71 |
结果说明:只 fine-tune VIMO 已经降低 W-MPJPE 和 RTE;进一步 fine-tune 后三项指标都最好,说明 EmbodMocap 的 RGB-D / camera / SMPL paired data 对 camera-world prediction 和 human reconstruction 都有帮助。
5.2 Dual-view capture vs monocular / single-view optimization
Figure 10 解读:作者在 Vicon optical mocap studio 中构建了对照实验:同一 actor、同一家具场景下,用 optical mocap 作为 ground truth,同时用两台 iPhone 录制。图中 zoom-in 展示 dual-view 相比 single-view 更能把人体轨迹放到正确 scene depth 上;论文还提到 dual-view scene calibration 约 5cm,而 single-view 超过 30cm。
Optical studio comparison,5 sequences / 1 participant / 9420 frames:
| Method | WA-MPJPE@100 ↓ | W-MPJPE@100 ↓ | WA-MPJPE@500 ↓ | W-MPJPE@500 ↓ | WA-MPJPE@1000 ↓ | W-MPJPE@1000 ↓ | RTE ↓ |
|---|---|---|---|---|---|---|---|
| GVHMR | 66.56 | 123.44 | 124.61 | 333.34 | 179.47 | 593.79 | 1.85 |
| Single-View V1 | 124.68 | 218.22 | 233.06 | 489.11 | 297.83 | 768.31 | 2.71 |
| Single-View V2 | 108.31 | 211.83 | 231.41 | 357.22 | 338.42 | 762.80 | 3.65 |
| Dual View | 56.61 | 72.86 | 76.90 | 99.75 | 119.45 | 169.11 | 1.13 |
该结果支撑论文最重要的设计选择:dual-view 不只是多一台相机,而是显著缓解 occlusion / self-occlusion 与沿相机朝向的 depth ambiguity,尤其 chunk 越长,single-view 的累计 alignment error 越明显。
5.3 Ablation on optimization losses
| IoU ↑ | Reproj ↓ | Depth ↓ | Jitter ↓ | |||||
|---|---|---|---|---|---|---|---|---|
| ✗ | ✓ | ✓ | ✓ | ✓ | 54.3 | 44.2 | 2.372 | 0.0371 |
| ✓ | ✗ | ✓ | ✓ | ✓ | 72.5 | 10.9 | 0.081 | 0.0131 |
| ✓ | ✓ | ✗ | ✓ | ✓ | 72.3 | 11.1 | 0.079 | 0.0130 |
| ✓ | ✓ | ✓ | ✗ | ✓ | 72.1 | 10.4 | 0.087 | 0.0160 |
| ✓ | ✓ | ✓ | ✓ | ✗ | 59.3 | 20.4 | 0.609 | 0.0126 |
| ✓ | ✓ | ✓ | ✓ | ✓ | 73.0 | 9.3 | 0.078 | 0.0128 |
最关键的 ablation 是去掉 和 :无 tracking 时 IoU 从 73.0 掉到 54.3、Reproj 从 9.3 升到 44.2、Depth 从 0.078 升到 2.372;无 3D keypoint 时 IoU 只有 59.3、Depth 为 0.609。说明 dual-view track stitching 与 triangulated 3D joints 是解决深度歧义和跨视角一致性的核心。
5.4 Physics-based character animation
Figure 11a–11b 解读:该组合图展示四个基础 skills 和两个新增 skills 的 qualitative comparison。Prone 与 Support 的意义在于它们比简单 locomotion 更依赖真实 contact:尤其 Support 要用手承重且脚保持靠近,对 reference motion 和 contact alignment 更敏感,因此能更好检验 EmbodMocap 数据的物理可用性。
核心 quantitative rows:
| Task | Data | Clips | Duration (min) | Success Rate ↑ | Contact Error (cm) ↓ | APD ↑ |
|---|---|---|---|---|---|---|
| Follow | Optical Mocap | 12 | 1.59 | 99.9 | 6.0 | 20.17 ± 0.19 |
| Follow | Ours Full | 148 | 22.43 | 99.8 | 6.2 | 19.69 ± 0.32 |
| Follow | Monocular | 148 | 22.43 | 98.0 | 7.2 | 19.85 ± 0.39 |
| Climb | Optical Mocap | 7 | 0.28 | 99.9 | 2.7 | 22.03 ± 0.30 |
| Climb | Ours Full | 21 | 1.54 | 99.9 | 1.8 | 22.22 ± 0.27 |
| Climb | Monocular | 21 | 1.54 | 99.2 | 1.8 | 21.34 ± 0.38 |
| Sit | Optical Mocap | 20 | 4.08 | 98.0 | 5.5 | 16.07 ± 0.39 |
| Sit | Ours Full | 80 | 8.05 | 99.9 | 4.7 | 15.90 ± 0.51 |
| Sit | Monocular | 80 | 8.05 | 98.4 | 5.7 | 15.80 ± 0.51 |
| Lie | Optical Mocap | 10 | 2.52 | 89.0 | 17.5 | 8.76 ± 0.14 |
| Lie | Ours Full | 39 | 4.25 | 89.4 | 18.8 | 8.57 ± 0.10 |
| Lie | Monocular | 39 | 4.25 | 81.2 | 21.0 | 8.14 ± 0.10 |
| Prone | Ours Full | 3 | 0.26 | 75.4 | 16.5 | 17.58 ± 0.69 |
| Prone | Monocular | 3 | 0.26 | 71.2 | 16.5 | 16.18 ± 0.30 |
| Support | Ours Full | 8 | 0.97 | 66.0 | 4.9 | 21.08 ± 0.59 |
| Support | Monocular | 8 | 0.97 | 20.6 | 6.4 | 20.94 ± 0.48 |
结果解读:低难度 Follow / Climb / Sit 上,Ours Full 已接近或超过 optical mocap;Lie 上 Ours Full 成功率 89.4,高于 optical 89.0 和 monocular 81.2;最能拉开差距的是 Support,Ours Full 成功率 66.0,而 Monocular 只有 20.6,说明单目 reference motion 在高接触难度任务中会严重退化。
5.5 Scene-aware tracking and robot control
| Scene | Clips | Duration (min) | Success Rate | Fail Rate | Successful Episode Len (s) | Failed Episode Len (s) |
|---|---|---|---|---|---|---|
| a | 14 | 12.31 | 87.2 | 12.8 | 9.97 ± 0.21 | 3.94 ± 2.10 |
| b | 6 | 3.62 | 96.7 | 3.3 | 9.99 ± 0.12 | 4.16 ± 2.38 |
| c | 12 | 7.87 | 95.9 | 4.1 | 9.98 ± 0.17 | 5.43 ± 2.18 |
| d | 7 | 5.06 | 90.4 | 9.6 | 9.96 ± 0.21 | 4.44 ± 1.92 |
Figure 12 解读:该图展示真实 humanoid robot 模仿视频中的人类动作。实验选择 ground-contact-rich motions,包括 locomotion 和 cartwheel,说明数据不只适合离线重建,还能通过 sim-to-real RL 训练实际机器人策略。论文报告策略部署在 21-DoF High Torque Hi humanoid 上,成功模仿全部测试动作。
5.6 Limitations and conclusion
作者明确列出的限制包括:iPhone LiDAR 超过约 5m 后无法记录可靠 depth;场景中有大量 moving objects 会破坏 SLAM;极亮光照会导致 COLMAP failure 和错误 registration。未来方向包括引入更鲁棒的 SfM 工具(如 H-Loc)和自动 iPhone synchronization app,减少人工同步成本。
总体结论:EmbodMocap 的贡献是一个低成本、可移动、可扩展的 4D human-scene capture pipeline。实验中 dual-view 明显优于 monocular / single-view;数据能提升 EMDB reconstruction,支持 physics-based interaction skill training,并可用于真实 humanoid robot imitation。它的主要价值在数据与系统层面:让 embodied AI 获得更接近真实世界的 scene-conditioned human motion。