Download ufd_evalkit/run_eval.py from KCBtheone/SplatAtlas: direct link, hf CLI and curl.
- Browser
- Download file 4.58 kB
-
https://huggingface.co/KCBtheone/SplatAtlas/resolve/main/ufd_evalkit/run_eval.py
- Command line
-
hf download hf://KCBtheone/SplatAtlas/ufd_evalkit/run_eval.py
-
curl -L -o run_eval.py https://huggingface.co/KCBtheone/SplatAtlas/resolve/main/ufd_evalkit/run_eval.py
4.58 kB
| import os | |
| import json | |
| class NpEncoder(json.JSONEncoder): | |
| def default(self, obj): | |
| if hasattr(obj, 'item'): | |
| return obj.item() | |
| return super().default(obj) | |
| import argparse | |
| import shutil | |
| import numpy as np | |
| import torch | |
| import sys | |
| sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) | |
| from core.registry import METHOD_REGISTRY | |
| import methods | |
| from photometric import compute_photometric_metrics | |
| from geometric import compute_geometric_pathology | |
| from alignment import assess_manifold_collapse | |
| def load_cameras_from_json(cam_path): | |
| if not os.path.exists(cam_path): return [] | |
| with open(cam_path, 'r') as f: cams_data = json.load(f) | |
| class DummyCam: | |
| def __init__(self, center): | |
| self.camera_center = torch.tensor(center, dtype=torch.float32) | |
| return [DummyCam(c['center']) for c in cams_data if 'center' in c] | |
| def parse_args(): | |
| parser = argparse.ArgumentParser() | |
| parser.add_argument("--method", type=str, required=True) | |
| parser.add_argument("--scene", type=str, required=True) | |
| parser.add_argument("--render_dir", type=str, required=True) | |
| parser.add_argument("--gt_dir", type=str, required=True) | |
| parser.add_argument("--ply_path", type=str, required=True) # 保持参数兼容外层流水线 | |
| parser.add_argument("--output_json", type=str, required=True) | |
| parser.add_argument("--prior_type", type=str, default="none") | |
| parser.add_argument("--depth_dir", type=str, default="") | |
| parser.add_argument("--skip_quarantine", action="store_true") | |
| parser.add_argument("--colmap_dir", type=str, default="") | |
| return parser.parse_args() | |
| def main(): | |
| args = parse_args() | |
| os.makedirs(os.path.dirname(args.output_json), exist_ok=True) | |
| # 从 ply_path 中反向推导出 model_path 和 iteration,实现无缝过渡 | |
| model_path = args.ply_path.split('/point_cloud/')[0] | |
| try: | |
| iteration = int(args.ply_path.split('/iteration_')[1].split('/')[0]) | |
| except IndexError: | |
| iteration = 30000 | |
| # 1. 实例化变体并加载资产 | |
| model_class = methods.load_method(args.method) | |
| _OUTDOOR_360 = {"bicycle", "flowers", "garden", "stump", "treehill"} | |
| _res = 4 if args.scene in _OUTDOOR_360 else 2 | |
| dataset_config = {"source_path": args.colmap_dir, "model_path": model_path, "resolution": _res} | |
| model = model_class(dataset_config, hyperparams={}) | |
| try: | |
| model.load(model_path, iteration) | |
| except Exception as e: | |
| print(f"❌ [Eval] 模型资产加载失败: {e}") | |
| return | |
| cams = load_cameras_from_json(os.path.join(model_path, "cameras.json")) | |
| # 2. 调用重构后的几何病理学检测 | |
| geo_metrics = compute_geometric_pathology(model, cameras=cams) | |
| flags = geo_metrics.get("pathology_flags", []) | |
| # 3. 调用重构后的流形坍塌检测 | |
| colmap_ply_path = os.path.join(args.colmap_dir, "sparse", "0", "points3D.ply") if args.colmap_dir else None | |
| alignment_res = assess_manifold_collapse(model, model_path, colmap_ply_path=colmap_ply_path) | |
| if alignment_res.get("manifold_collapse", False): | |
| flags.append("MANIFOLD_COLLAPSE") | |
| pass | |
| else: | |
| del model; torch.cuda.empty_cache() | |
| photo_metrics = compute_photometric_metrics(args.render_dir, args.gt_dir) | |
| if args.depth_dir and os.path.exists(args.depth_dir): | |
| depth_vars = [np.var(np.load(os.path.join(args.depth_dir, f))[np.load(os.path.join(args.depth_dir, f)) > 0.05]) | |
| for f in os.listdir(args.depth_dir) if f.endswith('.npy')] | |
| mean_depth_var = np.mean(depth_vars) if depth_vars else 1.0 | |
| geo_metrics["mean_depth_variance"] = round(float(mean_depth_var), 4) | |
| if mean_depth_var < 0.01: | |
| flags.append("FLAT_WALL_COLLAPSE") | |
| geo_metrics["pathology_flags"] = flags | |
| report = { | |
| "method": args.method, | |
| "scene": args.scene, | |
| "prior_type": args.prior_type, | |
| "photometric": photo_metrics, | |
| "geometric": geo_metrics, | |
| "pathology_flags": list(set(flags)) | |
| } | |
| with open(args.output_json, 'w') as f: | |
| json.dump(report, f, indent=4) | |
| if len(flags) > 0 and not args.skip_quarantine: | |
| master_log_path = os.path.join(os.path.dirname(model_path), "pathology_master_log.txt") | |
| with open(master_log_path, "a") as log_f: | |
| log_f.write(f"Method: {args.method} | Scene: {args.scene} | Path: {model_path} | Flags: {','.join(list(set(flags)))}\n") | |
| if __name__ == "__main__": | |
| main() | |