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=100lr=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_orienttranslkp3d_loss_weight=1.0kp3d_smooth_loss_weight=1.0num_iters=200lr=1e-2;第二阶段优化 global_orient, betas, body_pose, translkp3d_loss_weight=2.0、两视角 reproj_loss_weight=2.0、smooth 类权重为 1.0、prior regularization 为 10.0、motion/kp3d acceleration 权重为 5num_iters=300lr=1e-2config.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 默认 indoor depth_trunc=4.0、outdoor depth_trunc=5.0
  • Calibration objective:论文主公式列出 tracking + Chamfer + bundle adjustment;released optim_human_cam.py 还默认加入 p2p loss,并通过 config.yaml 打开。
  • Fast profileconfig_fast.yaml 不是论文结果配置,而是 release 中为了更快处理 mesh + motion 的工程配置,例如 scene voxel_size=0.02、COLMAP images 200、VGGT samples 100、keyframes 30

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_db
def 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, tracks
def 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 ConceptSource FileKey Class/Function
Unified stage runner / 16 processing stepsembod_mocap/run_stages.pyfull_steps, step commands for SAI, scene reconstruction, sequence processing, calibration, motion optimization
Standard / fast pipeline configembod_mocap/config.yaml, embod_mocap/config_fast.yamlsteps.sai, steps.recon_scene, steps.vggt_track, steps.optim_human_cam, steps.optim_motion
Checkpoint / model pathsembod_mocap/config_paths.pyPATHS.vimo_ckpt, PATHS.sam2_ckpt, PATHS.lingbotdepth_ckpt, PATHS.vggt_ckpt
Stage I TSDF scene reconstructionembod_mocap/processor/unproj_scene.pytsdf_clean, unproj_depth, vggt_depth_predict
Stage II masks/depth/keyframesembod_mocap/processor/process_depth_mask.pygenerate_masks, filter_points2d_with_masks, keyframe selection flags
Stage II / III VGGT correspondencesembod_mocap/processor/vggt_track.pyvggt_track_pair, visualize_vggt_tracks
Stage III camera calibrationembod_mocap/processor/optim_human_cam.pyoptim_cam, apply_rigid_to_RT_torch, dense_ba_loss_fn use
Stage IV world-space SMPLifyembod_mocap/processor/optim_motion.pytriangulate_sequence, kp3d_smoothing, smplify_optimization
Contact alignment for downstream embodied tasksembod_mocap/processor/align_contact.pycontact-marker based alignment invoked as step 16
VIMO/HMR model used for SMPL priorembod_mocap/human/backbone/vimo.py, embod_mocap/human/backbone/hmr2.pyHMR_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 与已有数据集的关键对比:

DatasetPublicationMain devicesTotal costMeshDynamic annotationOutdoor
PROXICCV 2019Structure Sensor + Kinect-One2K
RICHCVPR 2022Leica RTC360 + 6–8 static cams + 1 dynamic cam20K+
EgoBodyECCV 20225 Kinect + Hololens29K
SLOPER4DCVPR 2023Noitom PN+NUC11 + Ouster-os1 LiDAR + DJI-Action2+TLS20K
EMDBICCV 2023EM sensors + 1 dynamic cam15K
NymeriaECCV 2024Xsens + Aria Wristband + 2 Aria60K+
EmbodMocapCVPR 20261 scanner-like iPhone scene pass + 2 dynamic iPhones1K

4.2 Evaluation tasks and baselines

论文用三类 downstream tasks 验证数据价值:

  1. Monocular human-scene reconstruction:baseline 使用 做 SLAM / camera 和 local point maps,VIMO 做 metric-scale human motion reconstruction;在 EMDB subset 2 上用 WA-MPJPE、W-MPJPE 和 RTE 评估。
  2. 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。
  3. 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: indoor key_frame_dist=0.1,outdoor 0.15
  • recon_scene: indoor/outdoor depth_trunc=4.0/5.0sdf_trunc=0.1voxel_size=0.01vggt_refine=false
  • get_frames: down_scale=2slice_views: jpeg_quality=5remove_raw_images=true
  • colmap_human_cam: colmap_num=400min_valid_ratio=0.2generate_keyframes: min_tracks=10num_keyframes=50min_keyframes=20
  • process_depth_mask: need_all_depth_mask=truedepth_refine_max_size=960depth_refine_chunk_size=4lang_sam_chunk_size=5
  • vggt_track: vggt_track_samples=200unproj_human: indoor stride 30、outdoor stride 40
  • 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=cudaNUM_WORKERS=15IMG_RES=256SEQ_LEN=16BATCH_SIZE=24LR=1e-5LR2=3e-5WARMUP_STEPS=3000MAX_STEP=250000OPT=AdamWWD=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 VIMOWA-MPJPE ↓W-MPJPE ↓RTE ↓
83.56229.041.78
82.89222.931.73
82.21220.651.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:

MethodWA-MPJPE@100 ↓W-MPJPE@100 ↓WA-MPJPE@500 ↓W-MPJPE@500 ↓WA-MPJPE@1000 ↓W-MPJPE@1000 ↓RTE ↓
GVHMR66.56123.44124.61333.34179.47593.791.85
Single-View V1124.68218.22233.06489.11297.83768.312.71
Single-View V2108.31211.83231.41357.22338.42762.803.65
Dual View56.6172.8676.9099.75119.45169.111.13

该结果支撑论文最重要的设计选择:dual-view 不只是多一台相机,而是显著缓解 occlusion / self-occlusion 与沿相机朝向的 depth ambiguity,尤其 chunk 越长,single-view 的累计 alignment error 越明显。

5.3 Ablation on optimization losses

IoU ↑Reproj ↓Depth ↓Jitter ↓
54.344.22.3720.0371
72.510.90.0810.0131
72.311.10.0790.0130
72.110.40.0870.0160
59.320.40.6090.0126
73.09.30.0780.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:

TaskDataClipsDuration (min)Success Rate ↑Contact Error (cm) ↓APD ↑
FollowOptical Mocap121.5999.96.020.17 ± 0.19
FollowOurs Full14822.4399.86.219.69 ± 0.32
FollowMonocular14822.4398.07.219.85 ± 0.39
ClimbOptical Mocap70.2899.92.722.03 ± 0.30
ClimbOurs Full211.5499.91.822.22 ± 0.27
ClimbMonocular211.5499.21.821.34 ± 0.38
SitOptical Mocap204.0898.05.516.07 ± 0.39
SitOurs Full808.0599.94.715.90 ± 0.51
SitMonocular808.0598.45.715.80 ± 0.51
LieOptical Mocap102.5289.017.58.76 ± 0.14
LieOurs Full394.2589.418.88.57 ± 0.10
LieMonocular394.2581.221.08.14 ± 0.10
ProneOurs Full30.2675.416.517.58 ± 0.69
ProneMonocular30.2671.216.516.18 ± 0.30
SupportOurs Full80.9766.04.921.08 ± 0.59
SupportMonocular80.9720.66.420.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

SceneClipsDuration (min)Success RateFail RateSuccessful Episode Len (s)Failed Episode Len (s)
a1412.3187.212.89.97 ± 0.213.94 ± 2.10
b63.6296.73.39.99 ± 0.124.16 ± 2.38
c127.8795.94.19.98 ± 0.175.43 ± 2.18
d75.0690.49.69.96 ± 0.214.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。