SplatAtlas / scripts /aggregate_surfel_hypothesis_all.py
KCBtheone's picture
Upload SplatAtlas benchmark pipeline code
23e73f9 verified
Raw
History Blame Contribute Delete
15.4 kB
#!/usr/bin/env python3
import json
from pathlib import Path
import pandas as pd
PROJECT = Path("/root/autodl-tmp/SplatAtlas")
OUT_ROOT = PROJECT / "outputs" / "surfel_hypothesis_all"
SOURCE_JSON_ROOT = PROJECT / "outputs" / "surfel_hypothesis"
RUN_INDEX = OUT_ROOT / "run_index.csv"
OUT_ROOT.mkdir(parents=True, exist_ok=True)
METHOD_GROUP = {
"vanilla_3dgs": "standard_3dgs",
"3dgs_dr": "standard_3dgs",
"3dgsmcmc": "standard_3dgs",
"aaags": "standard_3dgs_nondefault_checkpoint",
"absgs": "standard_3dgs",
"absgssgf": "standard_3dgs",
"analyticsplatting": "standard_3dgs",
"atomgs": "standard_3dgs",
"cdcgs": "standard_3dgs",
"coadaptgs": "standard_3dgs",
"conegs": "standard_3dgs",
"drkgs": "standard_3dgs",
"erankgs": "standard_3dgs",
"ges": "standard_3dgs",
"ghap": "standard_3dgs",
"gslpm": "standard_3dgs",
"hogs": "standard_3dgs_nondefault_checkpoint",
"lapisgs": "standard_3dgs",
"lightgaussian": "standard_3dgs",
"minisplatting": "standard_3dgs",
"minisplattingsgf": "standard_3dgs",
"mipsplatting": "standard_3dgs",
"opti3dgs": "standard_3dgs",
"pixelgs": "standard_3dgs",
"pixelgssgf": "standard_3dgs",
"rdogaussian": "standard_3dgs",
"reactgs": "standard_3dgs",
"steepgs": "standard_3dgs",
"tamgs": "standard_3dgs_nondefault_checkpoint",
"gaussianpro": "geometry_aware_standard_or_usable",
"gof": "geometry_aware_standard_or_usable",
"pgsr": "geometry_aware_standard_or_usable",
"gsdf": "geometry_aware_standard_or_usable",
"gspull": "geometry_aware_standard_or_usable",
"2dgs": "surface_primitive_2dgs_disk_normal",
"trimgs": "surface_primitive_pca_only",
"gaussian_surfel": "gaussian_surfel_usable",
"scaffoldgs": "hierarchical_or_anchor_usable",
"octree_gs": "hierarchical_or_anchor_usable",
"lod_gs": "hierarchical_or_anchor_usable",
"sugar": "surface_mesh_coupled_usable",
}
METHODS = list(METHOD_GROUP.keys())
SCENES = ["barn", "caterpillar", "truck"]
def get(d, key):
return d.get(key, None)
def read_failure_tail(log_path, n=25):
p = PROJECT / log_path if not str(log_path).startswith("/") else Path(log_path)
if not p.exists():
return ""
lines = p.read_text(errors="replace").splitlines()
return "\n".join(lines[-n:])
rows = []
failures = []
run_index_df = None
if RUN_INDEX.exists():
run_index_df = pd.read_csv(RUN_INDEX)
else:
run_index_df = pd.DataFrame(columns=["method", "scene", "group", "status", "log_path", "json_path"])
for method in METHODS:
for scene in SCENES:
p = SOURCE_JSON_ROOT / f"{method}_{scene}" / "surfel_hypothesis_eval.json"
idx_rows = run_index_df[
(run_index_df.get("method") == method) &
(run_index_df.get("scene") == scene)
]
log_path = None
run_status = "not_in_run_index"
iteration_arg = ""
if len(idx_rows) > 0:
rr = idx_rows.iloc[-1]
log_path = rr.get("log_path", None)
run_status = rr.get("status", "unknown")
iteration_arg = rr.get("iteration_arg", "")
if not p.exists():
failures.append({
"method": method,
"scene": scene,
"group": METHOD_GROUP[method],
"status": run_status,
"iteration_arg": iteration_arg,
"json_path": str(p),
"log_path": log_path,
"tail": read_failure_tail(log_path) if log_path else "",
})
rows.append({
"method": method,
"scene": scene,
"group": METHOD_GROUP[method],
"status": "missing_json",
"iteration_arg": iteration_arg,
"json_path": str(p),
"log_path": log_path,
})
continue
try:
d = json.loads(p.read_text())
except Exception as e:
failures.append({
"method": method,
"scene": scene,
"group": METHOD_GROUP[method],
"status": f"json_read_error: {type(e).__name__}: {e}",
"iteration_arg": iteration_arg,
"json_path": str(p),
"log_path": log_path,
"tail": read_failure_tail(log_path) if log_path else "",
})
rows.append({
"method": method,
"scene": scene,
"group": METHOD_GROUP[method],
"status": "json_read_error",
"iteration_arg": iteration_arg,
"json_path": str(p),
"log_path": log_path,
})
continue
row = {
"method": method,
"scene": scene,
"group": METHOD_GROUP[method],
"status": "ok",
"iteration_arg": iteration_arg,
"json_path": str(p),
"log_path": log_path,
"ply_path": get(d, "ply_path"),
"n_gaussians_recon": get(d, "n_gaussians_recon"),
"n_recon_after_crop": get(d, "n_recon_after_crop"),
"n_recon_eval": get(d, "n_recon_eval"),
"n_gt_after_crop": get(d, "n_gt_after_crop"),
"n_surface_near": get(d, "n_surface_near"),
"surface_near_ratio": get(d, "surface_near_ratio"),
"n_normal_eval": get(d, "n_normal_eval"),
"tau": get(d, "tau"),
"surface_near_threshold": get(d, "surface_near_threshold"),
"distance_median": get(d, "distance_recon_to_gt_median"),
"distance_mean": get(d, "distance_recon_to_gt_mean"),
"has_standard_covariance_shape": get(d, "has_standard_covariance_shape"),
"has_v3_normal": get(d, "has_v3_normal"),
"has_2dgs_normal": get(d, "has_2dgs_normal"),
"has_explicit_normal": get(d, "has_explicit_normal"),
# Normal metrics.
"center_pca_normal_median_deg": get(d, "center_pca_normal_error_median_deg"),
"center_pca_normal_mean_deg": get(d, "center_pca_normal_error_mean_deg"),
"center_pca_normal_iqr_deg": get(d, "center_pca_normal_error_iqr_deg"),
"v3_normal_median_deg": get(d, "v3_normal_error_median_deg"),
"v3_normal_mean_deg": get(d, "v3_normal_error_mean_deg"),
"v3_normal_iqr_deg": get(d, "v3_normal_error_iqr_deg"),
"delta_v3_minus_center_pca_deg": get(d, "median_delta_v3_minus_center_pca_deg"),
"center_pca_better_than_v3": get(d, "center_pca_better_than_v3_by_median"),
"two_dgs_normal_median_deg": get(d, "two_dgs_normal_error_median_deg"),
"two_dgs_normal_mean_deg": get(d, "two_dgs_normal_error_mean_deg"),
"two_dgs_normal_iqr_deg": get(d, "two_dgs_normal_error_iqr_deg"),
"delta_2dgs_minus_center_pca_deg": get(d, "median_delta_2dgs_minus_center_pca_deg"),
"center_pca_better_than_2dgs": get(d, "center_pca_better_than_2dgs_by_median"),
"explicit_normal_median_deg": get(d, "explicit_normal_error_median_deg"),
"explicit_normal_mean_deg": get(d, "explicit_normal_error_mean_deg"),
"explicit_normal_iqr_deg": get(d, "explicit_normal_error_iqr_deg"),
"delta_explicit_minus_center_pca_deg": get(d, "median_delta_explicit_minus_center_pca_deg"),
# Surface confidence calibration.
"opacity_auc_surface": get(d, "opacity_sigmoid_auroc_surface_near"),
"opacity_ap_surface": get(d, "opacity_sigmoid_ap_surface_near"),
"opacity_spearman_minus_distance": get(d, "opacity_sigmoid_spearman_vs_minus_distance"),
"opacity_median": get(d, "opacity_sigmoid_median"),
"cov_log_anisotropy_median": get(d, "cov_log_anisotropy_sigma_median"),
"cov_anisotropy_ratio_median": get(d, "cov_anisotropy_sigma_ratio_median"),
"cov_anisotropy_auc_surface": get(d, "cov_log_anisotropy_sigma_auroc_surface_near"),
"cov_anisotropy_ap_surface": get(d, "cov_log_anisotropy_sigma_ap_surface_near"),
"cov_anisotropy_spearman_minus_distance": get(d, "cov_log_anisotropy_sigma_spearman_vs_minus_distance"),
"cov_anisotropy_spearman_minus_v3_error": get(d, "cov_log_anisotropy_sigma_spearman_vs_minus_v3_error"),
"cov_planarity_median": get(d, "cov_planarity_median"),
"cov_planarity_auc_surface": get(d, "cov_planarity_auroc_surface_near"),
"cov_planarity_ap_surface": get(d, "cov_planarity_ap_surface_near"),
"cov_planarity_spearman_minus_distance": get(d, "cov_planarity_spearman_vs_minus_distance"),
"cov_planarity_spearman_minus_v3_error": get(d, "cov_planarity_spearman_vs_minus_v3_error"),
"cov_linearity_median": get(d, "cov_linearity_median"),
"cov_scattering_median": get(d, "cov_scattering_median"),
"spatial_planarity_median": get(d, "spatial_pca_planarity_median"),
"spatial_planarity_auc_surface": get(d, "spatial_pca_planarity_auroc_surface_near"),
"spatial_planarity_spearman_minus_distance": get(d, "spatial_pca_planarity_spearman_vs_minus_distance"),
"spatial_planarity_spearman_minus_center_pca_error": get(d, "spatial_pca_planarity_spearman_vs_minus_center_pca_error"),
"spatial_linearity_median": get(d, "spatial_pca_linearity_median"),
"spatial_scattering_median": get(d, "spatial_pca_scattering_median"),
"gt_local_pca_planarity_median": get(d, "gt_local_pca_planarity_median"),
"gt_local_pca_linearity_median": get(d, "gt_local_pca_linearity_median"),
"gt_local_pca_scattering_median": get(d, "gt_local_pca_scattering_median"),
"wall_time_seconds": get(d, "wall_time_seconds"),
}
rows.append(row)
df = pd.DataFrame(rows)
fail_df = pd.DataFrame(failures)
aggregate_csv = OUT_ROOT / "surfel_hypothesis_all_aggregate.csv"
failure_csv = OUT_ROOT / "surfel_hypothesis_all_failures.csv"
method_mean_csv = OUT_ROOT / "surfel_hypothesis_all_method_mean.csv"
scene_mean_csv = OUT_ROOT / "surfel_hypothesis_all_scene_mean.csv"
report_md = OUT_ROOT / "surfel_hypothesis_all_report.md"
df.to_csv(aggregate_csv, index=False)
fail_df.to_csv(failure_csv, index=False)
ok = df[df["status"] == "ok"].copy()
numeric_cols = [
"surface_near_ratio",
"distance_median",
"center_pca_normal_median_deg",
"v3_normal_median_deg",
"two_dgs_normal_median_deg",
"delta_v3_minus_center_pca_deg",
"delta_2dgs_minus_center_pca_deg",
"opacity_auc_surface",
"cov_anisotropy_auc_surface",
"cov_planarity_auc_surface",
"spatial_planarity_auc_surface",
"cov_anisotropy_spearman_minus_distance",
"cov_planarity_spearman_minus_distance",
"opacity_spearman_minus_distance",
]
if len(ok):
method_mean = ok.groupby(["group", "method"], dropna=False)[numeric_cols].mean(numeric_only=True).reset_index()
scene_mean = ok.groupby(["scene"], dropna=False)[numeric_cols].mean(numeric_only=True).reset_index()
else:
method_mean = pd.DataFrame()
scene_mean = pd.DataFrame()
method_mean.to_csv(method_mean_csv, index=False)
scene_mean.to_csv(scene_mean_csv, index=False)
# Useful derived summaries.
num_expected = len(METHODS) * len(SCENES)
num_ok = int((df["status"] == "ok").sum())
num_fail = num_expected - num_ok
best_v3 = ok.dropna(subset=["v3_normal_median_deg"]).sort_values("v3_normal_median_deg").head(15)
best_2dgs = ok.dropna(subset=["two_dgs_normal_median_deg"]).sort_values("two_dgs_normal_median_deg").head(15)
weak_aniso = ok.dropna(subset=["cov_anisotropy_auc_surface"]).copy()
with open(report_md, "w") as f:
f.write("# Surfel Hypothesis Full Run Report\n\n")
f.write(f"- Expected cells: {num_expected}\n")
f.write(f"- Successful cells: {num_ok}\n")
f.write(f"- Failed/missing cells: {num_fail}\n")
f.write(f"- Aggregate CSV: `{aggregate_csv}`\n")
f.write(f"- Failure CSV: `{failure_csv}`\n")
f.write(f"- Method mean CSV: `{method_mean_csv}`\n")
f.write(f"- Scene mean CSV: `{scene_mean_csv}`\n\n")
f.write("## Group counts among successful cells\n\n")
if len(ok):
f.write(ok["group"].value_counts().to_frame("count").to_markdown())
f.write("\n\n")
f.write("## Best covariance-derived V3 normals, lower is better\n\n")
if len(best_v3):
cols = [
"method", "scene", "group",
"surface_near_ratio",
"v3_normal_median_deg",
"v3_normal_iqr_deg",
"center_pca_normal_median_deg",
"delta_v3_minus_center_pca_deg",
]
f.write(best_v3[cols].to_markdown(index=False))
else:
f.write("No V3 normal results.\n")
f.write("\n\n")
f.write("## 2DGS / disk normal results\n\n")
if len(best_2dgs):
cols = [
"method", "scene", "group",
"surface_near_ratio",
"two_dgs_normal_median_deg",
"two_dgs_normal_iqr_deg",
"center_pca_normal_median_deg",
"delta_2dgs_minus_center_pca_deg",
]
f.write(best_2dgs[cols].to_markdown(index=False))
else:
f.write("No 2DGS disk-normal results.\n")
f.write("\n\n")
f.write("## Mean by method\n\n")
if len(method_mean):
show_cols = [
"group", "method",
"surface_near_ratio",
"v3_normal_median_deg",
"two_dgs_normal_median_deg",
"center_pca_normal_median_deg",
"cov_anisotropy_auc_surface",
"cov_planarity_auc_surface",
"opacity_auc_surface",
]
existing = [c for c in show_cols if c in method_mean.columns]
f.write(method_mean[existing].to_markdown(index=False))
f.write("\n\n")
f.write("## Failures\n\n")
if len(fail_df):
f.write(fail_df[["method", "scene", "group", "status", "log_path"]].to_markdown(index=False))
else:
f.write("No failures.\n")
f.write("\n")
print("============================================================")
print("Aggregation done")
print("============================================================")
print(f"[WROTE] {aggregate_csv}")
print(f"[WROTE] {failure_csv}")
print(f"[WROTE] {method_mean_csv}")
print(f"[WROTE] {scene_mean_csv}")
print(f"[WROTE] {report_md}")
print("\n===== successful / expected =====")
print(num_ok, "/", num_expected)
print("\n===== failures =====")
if len(fail_df):
print(fail_df[["method", "scene", "group", "status", "log_path"]].to_string(index=False))
else:
print("No failures.")
print("\n===== best V3 normals =====")
if len(best_v3):
print(best_v3[[
"method", "scene", "surface_near_ratio",
"v3_normal_median_deg",
"center_pca_normal_median_deg",
"delta_v3_minus_center_pca_deg",
]].to_string(index=False))
else:
print("No V3 results.")
print("\n===== 2DGS / disk normal results =====")
if len(best_2dgs):
print(best_2dgs[[
"method", "scene", "surface_near_ratio",
"two_dgs_normal_median_deg",
"center_pca_normal_median_deg",
"delta_2dgs_minus_center_pca_deg",
]].to_string(index=False))
else:
print("No 2DGS disk normal results.")