Files
hand-motion-pipeline/scripts/repair_red_box_topology.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

15 lines
1.7 KiB
Python

"""Split one collinear T-junction; preserve all original vertices and surface geometry."""
from pathlib import Path
import json,trimesh,numpy as np
root=Path(__file__).resolve().parents[1];out=root/'output/depth_ablation_red_20260916';m=trimesh.load(root/'docs/上半.stl');old=m.copy()
c=np.bincount(m.edges_unique_inverse);boundary=m.edges_unique[c==1];edge=max(boundary,key=lambda e:np.linalg.norm(m.vertices[e[0]]-m.vertices[e[1]]));a,b=edge
v=m.vertices;ab=v[b]-v[a];t=(v-v[a])@ab/(ab@ab);dist=np.linalg.norm(v-(v[a]+t[:,None]*ab),axis=1);inside=np.flatnonzero((t>1e-7)&(t<1-1e-7)&(dist<1e-9));assert len(inside)==2
faces=m.faces.tolist();hit=[i for i,f in enumerate(faces) if a in f and b in f];assert len(hit)==1
face=faces.pop(hit[0]);k=next(k for k in range(3) if face[k] in edge and face[(k+1)%3] in edge);a,b,third=face[k],face[(k+1)%3],face[(k+2)%3]
inside=sorted(inside,key=lambda q:np.linalg.norm(v[q]-v[a]));chain=[a,*inside,b];faces.extend([[int(x),int(y),int(third)] for x,y in zip(chain[:-1],chain[1:])]);m=trimesh.Trimesh(vertices=v.copy(),faces=faces,process=False)
assert m.is_watertight and m.is_winding_consistent and m.volume>0
assert np.array_equal(m.vertices,old.vertices) and abs(m.area-old.area)<1e-10 and abs(m.volume-old.volume)<1e-10
m.export(out/'red_box_closed.ply')
(out/'mesh_repair.json').write_text(json.dumps({'method':'Split original long boundary edge at two existing collinear vertices (T-junction); no added vertices or geometric hole filling','before_faces':len(old.faces),'after_faces':len(m.faces),'watertight':m.is_watertight,'winding_consistent':m.is_winding_consistent,'area_change_m2':m.area-old.area,'volume_change_m3':m.volume-old.volume},indent=2))
print('Topology repaired with unchanged geometry',m.is_watertight)