Instructions to use jamie33/mind3d-trellis2 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Trellis
How to use jamie33/mind3d-trellis2 with Trellis:
# No code snippets available yet for this library. # To use this model, check the repository files and the library's documentation. # Want to help? PRs adding snippets are welcome at: # https://github.com/huggingface/huggingface.js
- Notebooks
- Google Colab
- Kaggle
Download code/eval_shape.py from jamie33/mind3d-trellis2: direct link, hf CLI and curl.
- Browser
- Download file 3.97 kB
-
https://huggingface.co/jamie33/mind3d-trellis2/resolve/main/code/eval_shape.py
- Command line
-
hf download hf://jamie33/mind3d-trellis2/code/eval_shape.py
-
curl -L -o eval_shape.py https://huggingface.co/jamie33/mind3d-trellis2/resolve/main/code/eval_shape.py
3.97 kB
| """Shape metrics against ShapeNetCore.v2.PC15k GT, following MinD-3D's tools/get_cd.py protocol | |
| (2048 points, pc_norm), plus a shared orientation search so methods with different canonical frames | |
| are compared fairly.""" | |
| import os | |
| import glob | |
| import json | |
| import argparse | |
| import collections | |
| import numpy as np | |
| import trimesh | |
| from scipy.spatial import cKDTree | |
| from scipy.optimize import linear_sum_assignment | |
| N_POINTS = 2048 | |
| FSCORE_TAU = 0.02 | |
| def pc_norm(pc): | |
| pc = pc - pc.mean(0) | |
| return pc / (2 * np.max(np.linalg.norm(pc, axis=1))) | |
| def rot_y(deg): | |
| t = np.deg2rad(deg) | |
| c, s = np.cos(t), np.sin(t) | |
| return np.array([[c, 0, s], [0, 1, 0], [-s, 0, c]]) | |
| UP_MAPS = { | |
| "y_up": np.eye(3), | |
| "z_up": np.array([[1, 0, 0], [0, 0, 1], [0, -1, 0]], dtype=np.float64), | |
| } | |
| CANDIDATES = [(up, az, rot_y(az) @ m) for up, m in UP_MAPS.items() for az in range(0, 360, 45)] | |
| def chamfer(a, b): | |
| d_ab = cKDTree(b).query(a)[0] | |
| d_ba = cKDTree(a).query(b)[0] | |
| return np.mean(d_ab ** 2) + np.mean(d_ba ** 2), d_ab, d_ba | |
| def fscore(d_ab, d_ba, tau): | |
| p = np.mean(d_ab < tau) | |
| r = np.mean(d_ba < tau) | |
| return 0.0 if p + r == 0 else 2 * p * r / (p + r) | |
| def emd(a, b): | |
| cost = np.linalg.norm(a[:, None] - b[None], axis=-1) | |
| r, c = linear_sum_assignment(cost) | |
| return cost[r, c].mean() | |
| def main(): | |
| parser = argparse.ArgumentParser() | |
| parser.add_argument("--gen_dir", required=True) | |
| parser.add_argument("--gt_root", default="/home/hubin/data/ShapeNetCore.v2.PC15k/ShapeNetCore.v2.PC15k") | |
| parser.add_argument("--test_list", default="/home/hubin/data/fMRI-Shape/annotations/core_test_list.txt") | |
| parser.add_argument("--out", required=True) | |
| parser.add_argument("--seed", type=int, default=0) | |
| args = parser.parse_args() | |
| gt_paths = {os.path.basename(p)[:-4]: p for p in glob.glob(f"{args.gt_root}/*/_/*/*.npy")} | |
| ids = [l.strip() for l in open(args.test_list) if l.strip()] | |
| rows = [] | |
| for obj in ids: | |
| cat, uid = obj.split("/") | |
| gen = [p for p in glob.glob(os.path.join(args.gen_dir, f"{cat}_{uid}.*")) if p.endswith((".ply", ".obj"))] | |
| if uid not in gt_paths or not gen: | |
| continue | |
| rng = np.random.default_rng(args.seed) | |
| gt = np.load(gt_paths[uid]) | |
| gt = pc_norm(gt[rng.choice(len(gt), N_POINTS, replace=False)].astype(np.float64)) | |
| mesh = trimesh.load(gen[0], force="mesh") | |
| pts = trimesh.sample.sample_surface(mesh, N_POINTS, seed=args.seed)[0].astype(np.float64) | |
| pts = pc_norm(pts) | |
| best = None | |
| for up, az, R in CANDIDATES: | |
| cd, d_ab, d_ba = chamfer(pts @ R.T, gt) | |
| if best is None or cd < best[0]: | |
| best = (cd, up, az, R, d_ab, d_ba) | |
| cd, up, az, R, d_ab, d_ba = best | |
| rows.append({ | |
| "id": obj, "cat": cat, "cd": cd, "emd": emd(pts @ R.T, gt), | |
| "fscore": fscore(d_ab, d_ba, FSCORE_TAU), "up": up, "azimuth": az, | |
| }) | |
| print(f"{obj} CD={cd * 1e3:.3f}e-3 EMD={rows[-1]['emd']:.4f} F={rows[-1]['fscore']:.3f} ({up},{az})", flush=True) | |
| by_cat = collections.defaultdict(list) | |
| for r in rows: | |
| by_cat[r["cat"]].append(r) | |
| summary = { | |
| "n": len(rows), | |
| "cd_x1e3": float(np.mean([r["cd"] for r in rows]) * 1e3), | |
| "emd": float(np.mean([r["emd"] for r in rows])), | |
| "fscore@0.02": float(np.mean([r["fscore"] for r in rows])), | |
| "per_category": {c: {"n": len(v), "cd_x1e3": float(np.mean([r["cd"] for r in v]) * 1e3), | |
| "emd": float(np.mean([r["emd"] for r in v]))} for c, v in sorted(by_cat.items())}, | |
| "chosen_orientation": collections.Counter(f"{r['up']}/{r['azimuth']}" for r in rows).most_common(), | |
| } | |
| with open(args.out, "w") as f: | |
| json.dump({"summary": summary, "rows": rows}, f, indent=1) | |
| print(json.dumps({k: v for k, v in summary.items() if k != "per_category"}, indent=1)) | |
| if __name__ == "__main__": | |
| main() | |