Files
hand-motion-pipeline/scripts/audit_red_depth_metrics.py
T
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

25 lines
2.3 KiB
Python

"""Independent distance sign audit and paired metric recomputation from saved geometry."""
from pathlib import Path
import numpy as np,trimesh,open3d as o3d,json
from red_box_distance import signed_distance
ROOT=Path(__file__).resolve().parents[1];out=ROOT/'output/depth_ablation_red_20260916';a=np.load(out/'foreground_left_depth_comparison.npz');m=trimesh.load(out/'red_box_closed.ply',process=False)
scene=o3d.t.geometry.RaycastingScene();scene.add_triangles(o3d.t.geometry.TriangleMesh.from_legacy(o3d.geometry.TriangleMesh(o3d.utility.Vector3dVector(m.vertices),o3d.utility.Vector3iVector(m.faces))))
rows=json.loads((out/'foreground_left_frame_metrics.json').read_text());report=json.loads((out/'comparison_metrics.json').read_text())
for i in np.flatnonzero(a['paired']):
T=a['object_pose'][i];v=a['verts_before'][i];j=a['joints_before'][i];groups=[np.argsort(np.linalg.norm(v-j[k],axis=1))[:20] for k in [4,8,12,16,20]]
for label in ['before','after']:
local=(a['verts_'+label][i]-T[:3,3])@T[:3,:3];sd=signed_distance(scene,m,local)
gap=[float(np.min(np.abs(sd[g]))*1000) for g in groups]
rows[i][label]={'penetrating_vertex_fraction':float((sd<-.001).mean()),'max_vertex_penetration_mm':float(max(0,-sd.min())*1000),'nearest_fingertip_surface_gap_mm':min(gap),'fingertip_surface_gaps_mm':gap}
if i%60==0:print('audited',i,flush=True)
s=report['hands']['foreground_left']
for label in ['before','after']:
for key in ['penetrating_vertex_fraction','max_vertex_penetration_mm','nearest_fingertip_surface_gap_mm']:
x=np.array([rows[i][label][key] for i in np.flatnonzero(a['paired'])]);s[label][key]={'median':float(np.median(x)),'p95':float(np.percentile(x,95)),'mean':float(np.mean(x))}
report['distance_sign']='Unsigned nearest surface distance with solid-angle winding number; outside bounding box explicitly exterior. Ray parity produced false inside classifications for this CAD and was replaced.'
# Geometry and data consistency invariants.
d=a['translation_camera'];assert np.max(np.abs(a['verts_after']-a['verts_before']-d[:,None,:]))<1e-6
assert np.max(np.abs(a['joints_after']-a['joints_before']-d[:,None,:]))<1e-6
assert np.isfinite(a['verts_after']).all();assert len(a['verts_before'])==315
(out/'foreground_left_frame_metrics.json').write_text(json.dumps(rows,indent=2));(out/'comparison_metrics.json').write_text(json.dumps(report,indent=2));print(json.dumps(s,indent=2))