Download tools/check_missing_renders.py from KCBtheone/SplatAtlas: direct link, hf CLI and curl.
- Browser
- Download file 5.65 kB
-
https://huggingface.co/KCBtheone/SplatAtlas/resolve/main/tools/check_missing_renders.py
- Command line
-
hf download hf://KCBtheone/SplatAtlas/tools/check_missing_renders.py
-
curl -L -o check_missing_renders.py https://huggingface.co/KCBtheone/SplatAtlas/resolve/main/tools/check_missing_renders.py
5.65 kB
| #!/usr/bin/env python3 | |
| # -*- coding: utf-8 -*- | |
| """ | |
| Diagnostic: check whether CoAdaptGS / LoD-GS have PLY, test renders, and metrics | |
| for the cells that are missing from outputs/phase5a/task_vapre_splatatlas_repro.csv. | |
| """ | |
| import json | |
| from pathlib import Path | |
| ROOT = Path("/root/autodl-tmp/SplatAtlas") | |
| OUTPUTS = ROOT / "outputs" | |
| # Cells missing from phase5a (from previous diagnostic) | |
| COADAPTGS_MISSING = [ | |
| # T&T (12) | |
| "Auditorium", "Ballroom", "Barn", "Caterpillar", "Courtroom", | |
| "Lighthouse", "Museum", "Palace", "Playground", "Temple", "Train", "Truck", | |
| # Mip-360 (9) | |
| "Bicycle", "Bonsai", "Counter", "Flowers", "Garden", "Kitchen", | |
| "Room", "Stump", "Treehill", | |
| # DB (2) | |
| "DrJohnson", "Playroom", | |
| ] | |
| LOD_GS_MISSING = [ | |
| # NS (8) | |
| "Chair", "Drums", "Ficus", "Hotdog", "Lego", "Materials", "Mic", "Ship", | |
| ] | |
| # Common alternate casings to try, since phase5a uses lowercase but | |
| # directory names sometimes use the canonical mixed case. | |
| def candidate_dirs(method: str, scene: str): | |
| cands = [ | |
| OUTPUTS / f"{method}_{scene}", | |
| OUTPUTS / f"{method}_{scene.lower()}", | |
| OUTPUTS / f"{method}_{scene.capitalize()}", | |
| ] | |
| seen = [] | |
| for c in cands: | |
| if c not in seen: | |
| seen.append(c) | |
| return seen | |
| def find_run_dir(method: str, scene: str): | |
| for d in candidate_dirs(method, scene): | |
| if d.exists(): | |
| return d | |
| # Fallback: glob anything matching | |
| matches = list(OUTPUTS.glob(f"{method}_*")) | |
| for m in matches: | |
| # match scene case-insensitively | |
| suffix = m.name[len(method) + 1:] | |
| if suffix.lower() == scene.lower(): | |
| return m | |
| return None | |
| def count_images(d: Path): | |
| if not d.exists(): | |
| return 0 | |
| n = 0 | |
| for ext in ("*.png", "*.jpg", "*.jpeg"): | |
| n += len(list(d.glob(ext))) | |
| return n | |
| def inspect_metrics_json(p: Path): | |
| if not p.exists(): | |
| return None | |
| try: | |
| obj = json.load(open(p, "r")) | |
| except Exception as e: | |
| return {"_error": str(e)} | |
| flat = {} | |
| def walk(o, prefix=""): | |
| if isinstance(o, dict): | |
| for k, v in o.items(): | |
| walk(v, f"{prefix}{k}.") | |
| elif isinstance(o, list): | |
| pass | |
| else: | |
| flat[prefix.rstrip(".")] = o | |
| walk(obj) | |
| keep = {} | |
| for k, v in flat.items(): | |
| kl = k.lower() | |
| if any(t in kl for t in ["psnr", "ssim", "lpips"]): | |
| keep[k] = v | |
| return keep or {"_no_metric_keys": list(flat.keys())[:10]} | |
| def check(method: str, scene: str): | |
| run = find_run_dir(method, scene) | |
| row = { | |
| "method": method, | |
| "scene": scene, | |
| "run_dir": str(run) if run else "MISSING", | |
| } | |
| if run is None: | |
| row.update({"ply": "-", "cameras": "-", "renders": "-", "gt": "-", | |
| "metrics_json": "-", "metrics_values": "-"}) | |
| return row | |
| ply = run / "point_cloud" / "iteration_30000" / "point_cloud.ply" | |
| cameras = run / "cameras.json" | |
| # test render dirs (typical 3DGS-family layout) | |
| test_root_candidates = [ | |
| run / "test" / "ours_30000", | |
| run / "test" / "ours_30000" / "30000", | |
| ] | |
| test_root = next((p for p in test_root_candidates if p.exists()), None) | |
| if test_root: | |
| renders_dir = test_root / "renders" | |
| gt_dir = test_root / "gt" | |
| else: | |
| # Fall back: any folder named renders / gt under run/ | |
| renders_list = list(run.rglob("renders")) | |
| gt_list = list(run.rglob("gt")) | |
| renders_dir = renders_list[0] if renders_list else None | |
| gt_dir = gt_list[0] if gt_list else None | |
| n_renders = count_images(renders_dir) if renders_dir else 0 | |
| n_gt = count_images(gt_dir) if gt_dir else 0 | |
| metrics_path = run / "metrics_test_iter30000.json" | |
| metrics_values = inspect_metrics_json(metrics_path) | |
| row.update({ | |
| "ply": "OK" if ply.exists() else "MISSING", | |
| "cameras": "OK" if cameras.exists() else "MISSING", | |
| "renders": f"{n_renders} imgs @ {renders_dir}" if renders_dir else "MISSING", | |
| "gt": f"{n_gt} imgs @ {gt_dir}" if gt_dir else "MISSING", | |
| "metrics_json": "OK" if metrics_path.exists() else "MISSING", | |
| "metrics_values": metrics_values if metrics_values else "-", | |
| }) | |
| return row | |
| def print_block(method: str, scenes): | |
| print(f"\n{'='*100}") | |
| print(f" {method} ({len(scenes)} missing scenes)") | |
| print(f"{'='*100}") | |
| summary = {"run_dir": 0, "ply": 0, "renders": 0, "metrics_json": 0} | |
| for s in scenes: | |
| r = check(method, s) | |
| print(f"\n--- {method} × {s} ---") | |
| print(f" run_dir : {r['run_dir']}") | |
| print(f" PLY : {r['ply']}") | |
| print(f" cameras.json : {r['cameras']}") | |
| print(f" test renders : {r['renders']}") | |
| print(f" test gt : {r['gt']}") | |
| print(f" metrics_json : {r['metrics_json']}") | |
| if isinstance(r['metrics_values'], dict): | |
| print(f" metrics_values: {r['metrics_values']}") | |
| if r['run_dir'] != "MISSING": | |
| summary["run_dir"] += 1 | |
| if r['ply'] == "OK": | |
| summary["ply"] += 1 | |
| if isinstance(r['renders'], str) and r['renders'].startswith(tuple("0123456789")): | |
| n = int(r['renders'].split()[0]) | |
| if n > 0: | |
| summary["renders"] += 1 | |
| if r['metrics_json'] == "OK": | |
| summary["metrics_json"] += 1 | |
| print(f"\n[Summary {method}]") | |
| for k, v in summary.items(): | |
| print(f" {k:<14}: {v} / {len(scenes)}") | |
| print_block("coadaptgs", COADAPTGS_MISSING) | |
| print_block("lod_gs", LOD_GS_MISSING) | |