"""Evaluate semantic predictions and render a compact comparison image.""" import json from pathlib import Path import matplotlib.pyplot as plt import numpy as np import yaml ROOT = Path(__file__).resolve().parents[1] def main(): with (ROOT / "conf" / "config.yaml").open(encoding="utf-8") as handle: config = yaml.safe_load(handle) input_dir = ROOT / config["paths"]["inference_dir"] required = [input_dir / "predictions.npy", input_dir / "targets.npy"] missing = [str(path.relative_to(ROOT)) for path in required if not path.exists()] if missing: raise FileNotFoundError( f"Missing inference outputs: {missing}. Run `python scripts/inference.py` first." ) predictions = np.load(input_dir / "predictions.npy") targets = np.load(input_dir / "targets.npy") classes = config["data"]["num_classes"] intersections = np.zeros(classes, dtype=np.float64) unions = np.zeros(classes, dtype=np.float64) for class_id in range(classes): predicted = predictions == class_id expected = targets == class_id intersections[class_id] = np.logical_and(predicted, expected).sum() unions[class_id] = np.logical_or(predicted, expected).sum() per_class_iou = np.divide(intersections, unions, out=np.zeros_like(intersections), where=unions > 0) metadata_path = input_dir / "metadata.npz" metadata = np.load(metadata_path) if metadata_path.exists() else None metrics = { "pixel_accuracy": float((predictions == targets).mean()), "mean_iou": float(per_class_iou.mean()), "per_class_iou": per_class_iou.tolist(), "samples": int(len(predictions)), "data_source": str(metadata["data_source"]) if metadata is not None else "unknown", "protocol": str(metadata["protocol"]) if metadata is not None else "unknown", } output_dir = ROOT / config["paths"]["evaluation_dir"] output_dir.mkdir(parents=True, exist_ok=True) with (output_dir / "metrics.json").open("w", encoding="utf-8") as handle: json.dump(metrics, handle, indent=2) figure, axes = plt.subplots(2, 2, figsize=(7, 7)) for index, axis in enumerate(axes.flat): sample = index // 2 image = targets[sample] if index % 2 == 0 else predictions[sample] axis.imshow(image, vmin=0, vmax=classes - 1, cmap="terrain") axis.set_title(("Target" if index % 2 == 0 else "Prediction") + f" {sample}") axis.axis("off") figure.tight_layout() figure.savefig(output_dir / "comparison.png", dpi=120) plt.close(figure) print(f"pixel_accuracy={metrics['pixel_accuracy']:.6f} mean_iou={metrics['mean_iou']:.6f}") print(f"evaluation={output_dir.relative_to(ROOT)}") if __name__ == "__main__": main()