Source code for openalea.phenomenal.multi_view_reconstruction.evaluation

import numpy

from openalea.phenomenal.multi_view_reconstruction import project_voxel_centers_on_image


[docs] def segmentation_metrics(img_ref, img_src): """ Compute TP, FP, FN, TN + IoU + Dice between two binary images. Parameters ---------- img_ref : array-like Ground truth (reference) img_src : array-like Prediction Returns ------- dict with: TP, FP, FN, TN (counts) IoU Dice """ # Convert to boolean (robust to 0/1, 0/255, etc.) ref = numpy.asarray(img_ref).astype(bool) src = numpy.asarray(img_src).astype(bool) if ref.shape != src.shape: raise ValueError(f"Shape mismatch: {ref.shape} vs {src.shape}") # Confusion matrix components TP = numpy.logical_and(ref, src).sum() FP = numpy.logical_and(~ref, src).sum() FN = numpy.logical_and(ref, ~src).sum() TN = numpy.logical_and(~ref, ~src).sum() # Metrics (safe divisions) union = TP + FP + FN iou = TP / union if union != 0 else 1.0 denom_dice = 2 * TP + FP + FN dice = (2 * TP) / denom_dice if denom_dice != 0 else 1.0 precision = TP / (TP + FP) if (TP + FP) else 0 recall = TP / (TP + FN) if (TP + FN) else 0 return { "TP": TP, "FP": FP, "FN": FN, "TN": TN, "precision": precision, "recall": recall, "IoU": iou, "Dice": dice, }
[docs] def reconstruction_metrics(voxels_grid, image_views): """ Compute mean metrics over all views. """ all_metrics = [] for image_view in image_views.values(): img_src = project_voxel_centers_on_image( voxels_grid.voxels_position, voxels_grid.voxels_size, image_view.image.shape, image_view.projection, ) metrics = segmentation_metrics(image_view.image, img_src) all_metrics.append(metrics) # Aggregate (mean over views) keys = all_metrics[0].keys() mean_metrics = { k: numpy.mean([m[k] for m in all_metrics]) for k in keys } return mean_metrics