All checks were successful
Verification / Is-Buildable (push) Successful in 2m43s
- report valid coverage and depth percentiles even when XYZ ground truth is absent - accept depth bounds and optional color-mapped PNG output for visual inspection - retain accuracy metrics when point_cloud.obj is available - add a batch helper that renders Markdown tables and optional JSON and PNG artifacts - document benchmark inputs, dataset limits, and visualization tradeoffs
84 lines
3.1 KiB
Python
Executable File
84 lines
3.1 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""Run scared_dataset_benchmark over many keyframes and print a Markdown table.
|
|
|
|
Usage:
|
|
scripts/scared_overview.py [--bench PATH] [--disparities N] [--png-dir DIR]
|
|
[--json-dir DIR] [--depth-range MIN_M MAX_M]
|
|
KEYFRAME_DIR...
|
|
|
|
Each KEYFRAME_DIR must hold Left_Image.png, Right_Image.png and
|
|
endoscope_calibration.yaml. Accuracy columns are filled in only for keyframes
|
|
that also contain point_cloud.obj.
|
|
"""
|
|
import argparse
|
|
import json
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
|
|
|
|
def run(bench, kf, disparities, png_dir, json_dir, depth_range):
|
|
label = "/".join(kf.rstrip("/").split("/")[-2:])
|
|
cmd = [bench, kf, str(disparities)]
|
|
if png_dir:
|
|
os.makedirs(png_dir, exist_ok=True)
|
|
cmd.append(os.path.join(png_dir, label.replace("/", "_") + ".png"))
|
|
else:
|
|
cmd.append("-")
|
|
if depth_range:
|
|
cmd += [str(depth_range[0]), str(depth_range[1])]
|
|
proc = subprocess.run(cmd, capture_output=True, text=True)
|
|
if proc.returncode != 0:
|
|
print(f"{label}: benchmark failed\n{proc.stderr}", file=sys.stderr)
|
|
return label, None
|
|
result = json.loads(proc.stdout)
|
|
if json_dir:
|
|
os.makedirs(json_dir, exist_ok=True)
|
|
with open(os.path.join(json_dir, label.replace("/", "_") + ".json"), "w") as f:
|
|
json.dump(result, f, indent=2)
|
|
return label, result
|
|
|
|
|
|
def fmt_mm(v):
|
|
return "" if v is None else f"{v * 1000:.2f}"
|
|
|
|
|
|
def fmt_pct(v):
|
|
return "" if v is None else f"{v * 100:.1f}"
|
|
|
|
|
|
def main():
|
|
ap = argparse.ArgumentParser()
|
|
ap.add_argument("--bench", default="build-opencv/src/cloud_point/scared_dataset_benchmark")
|
|
ap.add_argument("--disparities", type=int, default=160)
|
|
ap.add_argument("--png-dir")
|
|
ap.add_argument("--json-dir")
|
|
ap.add_argument("--depth-range", nargs=2, type=float, metavar=("MIN_M", "MAX_M"),
|
|
help="depth filter in metres (default: builder defaults 0.01..10)")
|
|
ap.add_argument("keyframes", nargs="+")
|
|
args = ap.parse_args()
|
|
|
|
rows = [run(args.bench, kf, args.disparities, args.png_dir, args.json_dir,
|
|
args.depth_range)
|
|
for kf in args.keyframes]
|
|
|
|
print("| keyframe | valid % | z p5 / median / p95 (mm) | match ms | GT | coverage % | MAE3D mm | RMSE3D mm | median mm | <1 mm % | <2 mm % | <5 mm % |")
|
|
print("|---|---|---|---|---|---|---|---|---|---|---|---|")
|
|
for label, r in rows:
|
|
if r is None:
|
|
print(f"| {label} | failed | | | | | | | | | | |")
|
|
continue
|
|
z = f"{r['z_p05_m']*1000:.0f} / {r['z_median_m']*1000:.0f} / {r['z_p95_m']*1000:.0f}"
|
|
gt = r.get("has_ground_truth", False)
|
|
print("| {} | {} | {} | {:.0f} | {} | {} | {} | {} | {} | {} | {} | {} |".format(
|
|
label, fmt_pct(r["valid_fraction"]), z, r["matching_ms"],
|
|
"yes" if gt else "no",
|
|
fmt_pct(r.get("coverage")), fmt_mm(r.get("mae_3d_m")),
|
|
fmt_mm(r.get("rmse_3d_m")), fmt_mm(r.get("median_3d_m")),
|
|
fmt_pct(r.get("within_1mm")), fmt_pct(r.get("within_2mm")),
|
|
fmt_pct(r.get("within_5mm"))))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|