segspace_app / metrics.py
functionNormally
Translate UI to French; keep code comments in English
d5fdcdd
Raw
History Blame Contribute Delete
2.24 kB
from typing import Dict, Optional
import numpy as np
from config import NUM_CLASSES, CLASS_NAMES, IGNORE_INDEX
def compute_metrics(pred: np.ndarray, gt: np.ndarray, num_classes: int = NUM_CLASSES) -> Dict:
pred = pred.astype(np.int64)
gt = gt.astype(np.int64)
labeled = gt != IGNORE_INDEX
pred_l = pred[labeled]
gt_l = gt[labeled]
if len(gt_l) == 0:
return {
"overall_acc": 0.0,
"miou": 0.0,
"per_class_acc": [None] * num_classes,
"per_class_iou": [None] * num_classes,
"confusion_matrix": [[0] * num_classes] * num_classes,
}
cm = np.zeros((num_classes, num_classes), dtype=np.int64)
for g, p in zip(gt_l, pred_l):
if 0 <= g < num_classes and 0 <= p < num_classes:
cm[g, p] += 1
overall_acc = float((gt_l == pred_l).mean())
per_class_acc, per_class_iou = [], []
for c in range(num_classes):
tp = cm[c, c]
gt_total = cm[c, :].sum()
pred_total = cm[:, c].sum()
union = gt_total + pred_total - tp
per_class_acc.append(float(tp / gt_total) if gt_total > 0 else None)
per_class_iou.append(float(tp / union) if union > 0 else None)
miou = float(np.nanmean([x if x is not None else np.nan for x in per_class_iou]))
return {
"overall_acc": overall_acc,
"miou": miou,
"per_class_acc": per_class_acc,
"per_class_iou": per_class_iou,
"confusion_matrix": cm.tolist(),
}
def metrics_markdown(metrics: Dict, title: str = "Metrics") -> str:
lines = [f"### {title}"]
lines.append(f"- Précision globale : **{metrics['overall_acc'] * 100:.2f}%**")
lines.append(f"- IoU moyen : **{metrics['miou'] * 100:.2f}%**")
lines.append("")
lines.append("| Classe | Précision | IoU |")
lines.append("|---|---:|---:|")
for name, acc, iou in zip(CLASS_NAMES, metrics["per_class_acc"], metrics["per_class_iou"]):
acc_s = "—" if acc is None else f"{acc * 100:.1f}%"
iou_s = "—" if iou is None else f"{iou * 100:.1f}%"
lines.append(f"| {name} | {acc_s} | {iou_s} |")
return "\n".join(lines)