blur-slam-bpn-code / scripts /eval_image_pair_metrics.py
zhaoshiwen's picture
Initial upload: BPN deblur pipeline code (scripts, triangle-splatting, BAGS, EVSSM forks)
c75b162 verified
Raw
History Blame Contribute Delete
2.51 kB
#!/usr/bin/env python3
"""Compute simple RGB PSNR/SSIM between two image folders."""
from __future__ import annotations
import argparse
import json
import math
from pathlib import Path
import cv2
import numpy as np
def images(path: Path) -> list[Path]:
return sorted([*path.glob("*.png"), *path.glob("*.jpg"), *path.glob("*.jpeg")])
def psnr(a: np.ndarray, b: np.ndarray) -> float:
mse = np.mean((a.astype(np.float32) - b.astype(np.float32)) ** 2)
if mse == 0:
return float("inf")
return 20 * math.log10(255.0 / math.sqrt(mse))
def ssim_gray(a: np.ndarray, b: np.ndarray) -> float:
# Lightweight global SSIM for fast prototype reporting.
a = cv2.cvtColor(a, cv2.COLOR_BGR2GRAY).astype(np.float64)
b = cv2.cvtColor(b, cv2.COLOR_BGR2GRAY).astype(np.float64)
c1 = (0.01 * 255) ** 2
c2 = (0.03 * 255) ** 2
mu_a, mu_b = a.mean(), b.mean()
var_a, var_b = a.var(), b.var()
cov = ((a - mu_a) * (b - mu_b)).mean()
return ((2 * mu_a * mu_b + c1) * (2 * cov + c2)) / ((mu_a ** 2 + mu_b ** 2 + c1) * (var_a + var_b + c2))
def main() -> None:
parser = argparse.ArgumentParser()
parser.add_argument("--ref", type=Path, required=True)
parser.add_argument("--pred", type=Path, required=True)
parser.add_argument("--out", type=Path)
args = parser.parse_args()
ref_paths = images(args.ref)
pred_paths = images(args.pred)
if len(ref_paths) != len(pred_paths):
raise ValueError(f"image count mismatch: {len(ref_paths)} vs {len(pred_paths)}")
rows = []
for ref, pred in zip(ref_paths, pred_paths):
a = cv2.imread(str(ref), cv2.IMREAD_COLOR)
b = cv2.imread(str(pred), cv2.IMREAD_COLOR)
if a is None or b is None:
raise ValueError(f"failed to read pair {ref} {pred}")
if a.shape != b.shape:
b = cv2.resize(b, (a.shape[1], a.shape[0]), interpolation=cv2.INTER_LINEAR)
rows.append({"name": ref.name, "psnr": psnr(a, b), "ssim": ssim_gray(a, b)})
summary = {
"num_images": len(rows),
"mean_psnr": float(np.mean([r["psnr"] for r in rows])),
"mean_ssim": float(np.mean([r["ssim"] for r in rows])),
"ref": str(args.ref),
"pred": str(args.pred),
}
print(json.dumps(summary, indent=2))
if args.out:
args.out.parent.mkdir(parents=True, exist_ok=True)
args.out.write_text(json.dumps({"summary": summary, "per_image": rows}, indent=2) + "\n")
if __name__ == "__main__":
main()