Files
hand-motion-pipeline/scripts/run_dynhamr_rgbd_20260915.py
liyang ae28d55f81 Update to 2026-09-17 pipeline snapshot; add weights, L20 assets and recording via Git LFS
Source: RGB-D -> Dyn-HaMR -> L20 retargeting -> FoundationPose -> reference repair -> SPIDER,
documented in docs/PIPELINE_LATEST.md and docs/SETUP_AND_WEIGHTS.md. Adds FoundationPose and
nvdiffrast upstream snapshots, requirements/pipeline_venv.txt and the FoundationPose weight
manifest/downloader.

Assets (Git LFS): weights/ (WiLoR detector, HandFlow denoiser, UniDepth-L), FoundationPose
checkpoints, HaMeR checkpoint, Dyn-HaMR HMP model and BMC constraints, L20 URDF/meshes, the
20260915_171525 D405 recording and the two box CADs. MANO models are not redistributed
(third_party/hamer/_DATA/data/mano/README.txt). Environments, caches and run outputs excluded.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-17 11:43:37 +08:00

50 lines
2.6 KiB
Python

"""Run both-hand Dyn-HaMR with measured intrinsics and RGB-D odometry."""
import json
import os
from pathlib import Path
import subprocess
import time
import numpy as np
ROOT = Path(__file__).resolve().parents[1]
OUT = ROOT / 'output/20260915_171525_dynhamr'
OUT.mkdir(parents=True, exist_ok=True)
SEQ = '20260915_171525'
dataset = OUT / 'dataset'
(dataset / 'videos').mkdir(parents=True, exist_ok=True)
video = dataset / 'videos' / (SEQ + '.mp4')
if not video.exists():
video.symlink_to(ROOT / 'docs' / SEQ / 'color.mp4')
camera = np.load(ROOT / 'output' / SEQ / 'rgbd_camera.npz')
assert camera['c2w'].shape == (352, 4, 4)
for kind, data in [('pose', camera['c2w']), ('intrinsics', np.tile(camera['intrinsics'], (352, 1)))]:
directory = OUT / 'rgbd_cameras' / kind
directory.mkdir(parents=True, exist_ok=True)
np.savez(directory / (SEQ + '.npz'), data=data.astype(np.float32), inds=np.arange(352))
(OUT / 'camera_provenance.json').write_text(json.dumps(dict(
source=str(ROOT / 'output' / SEQ / 'rgbd_camera.npz'),
method=str(camera['method']), adapter='ViPE file schema only; cameras estimated from D405 RGB-D',
hand_reconstruction='Dyn-HaMR', hands=['left', 'right']), indent=2))
dyn = ROOT / 'third_party/Dyn-HaMR'
env = os.environ.copy()
env.update(TORCH_HOME=str(ROOT / '.torch_cache'), HF_HOME=str(ROOT / '.hf_cache'),
HF_HUB_OFFLINE='1', TRANSFORMERS_OFFLINE='1', PYTHONUNBUFFERED='1',
MPLCONFIGDIR='/tmp/matplotlib-dynhamr', HYDRA_FULL_ERROR='1',
PYOPENGL_PLATFORM='egl', LD_LIBRARY_PATH='')
env['PATH'] = str(dyn / '.dynhamr/bin') + ':' + env['PATH']
env['PYTHONPATH'] = ':'.join(str(dyn / p) for p in ['dyn-hamr', 'third-party/hamer', 'third-party/hamer/third-party/ViTPose'])
cmd = [str(dyn / '.dynhamr/bin/python'), '-u', 'run_opt.py', 'data=video_vipe',
'data.root=' + str(dataset), 'data.seq="' + SEQ + '"',
'data.vipe_dir=' + str(OUT / 'rgbd_cameras'), 'data.frame_opts.fps=30',
'is_static=False', 'model.opt_scale=False', 'run_opt=True', 'run_vis=True',
'run_prior=True', '+data.vipe_pipeline=dynhamr_cameras',
'HMP.vid_path=' + str(video), 'hydra.run.dir=' + str(OUT / 'optimization')]
def status(stage, **kw):
(OUT / 'status.json').write_text(json.dumps(dict(stage=stage,
updated=time.strftime('%Y-%m-%d %H:%M:%S'), pid=os.getpid(), **kw), indent=2))
status('RUNNING', command=cmd)
with (OUT / 'run.log').open('a') as log:
result = subprocess.run(cmd, cwd=dyn / 'dyn-hamr', env=env, stdout=log, stderr=subprocess.STDOUT)
status('RECONSTRUCTION_PROCESS_EXITED' if result.returncode == 0 else 'FAILED', returncode=result.returncode)
raise SystemExit(result.returncode)