12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394 |
- import os
- import numpy as np
- import cv2
- from tqdm import tqdm
- from sklearn.metrics import jaccard_score, f1_score
- import pandas as pd
- from scipy.ndimage import distance_transform_edt
-
- def extract_border(mask):
- """Extract binary border from mask using morphological gradient."""
- kernel = np.ones((3, 3), dtype=np.uint8)
- dilated = cv2.dilate(mask, kernel, iterations=1)
- eroded = cv2.erode(mask, kernel, iterations=1)
- border = dilated - eroded
- return border
-
- def surface_dice(gt_mask, pred_mask, tolerance=2):
- gt_border = extract_border((gt_mask > 0).astype(np.uint8))
- pred_border = extract_border((pred_mask > 0).astype(np.uint8))
-
- if not np.any(gt_border) or not np.any(pred_border):
- return np.nan
-
- gt_dist = distance_transform_edt(1 - gt_border)
- pred_dist = distance_transform_edt(1 - pred_border)
-
- gt_match = pred_dist[gt_border > 0] <= tolerance
- pred_match = gt_dist[pred_border > 0] <= tolerance
-
- tp = np.count_nonzero(gt_match) + np.count_nonzero(pred_match)
- total = np.count_nonzero(gt_border) + np.count_nonzero(pred_border)
-
- return tp / total if total > 0 else np.nan
-
-
- def compute_metrics(gt_folder, pred_folder, output_csv="results.csv", tolerance=2):
- metrics = {
- "filename": [],
- "IoU": [],
- "Dice": [],
- "SurfaceDice": []
- }
-
- pred_files = sorted([f for f in os.listdir(pred_folder) if f.endswith(".png")])
-
- for filename in tqdm(pred_files):
- pred_path = os.path.join(pred_folder, filename)
- gt_path = os.path.join(gt_folder, filename)
-
- print(pred_path,gt_path)
-
- if not os.path.exists(gt_path):
- print(f"⚠️ There is no {filename}")
- continue
-
- gt_mask = cv2.imread(gt_path, cv2.IMREAD_GRAYSCALE)
- pred_mask = cv2.imread(pred_path, cv2.IMREAD_GRAYSCALE)
-
- if gt_mask is None or pred_mask is None or gt_mask.shape != pred_mask.shape:
- print(f"⚠️ No file : {filename}")
- continue
-
- gt_bin = (gt_mask > 0).astype(np.uint8).flatten()
- pred_bin = (pred_mask > 0).astype(np.uint8).flatten()
-
- iou = jaccard_score(gt_bin, pred_bin, zero_division=0)
- dice = f1_score(gt_bin, pred_bin, zero_division=0)
- surf_dice = surface_dice(gt_mask, pred_mask, tolerance)
-
- metrics["filename"].append(filename)
- metrics["IoU"].append(iou)
- metrics["Dice"].append(dice)
- metrics["SurfaceDice"].append(surf_dice)
-
- df = pd.DataFrame(metrics)
-
- if len(df) > 0:
- mean_row = {
- "filename": "MEAN",
- "IoU": df["IoU"].mean(),
- "Dice": df["Dice"].mean(),
- "SurfaceDice": df["SurfaceDice"].mean()
- }
- df = pd.concat([df, pd.DataFrame([mean_row])], ignore_index=True)
-
- df.to_csv(output_csv, index=False)
-
-
- compute_metrics(
- gt_folder="",
- pred_folder="",
- output_csv="",
- tolerance=2
- )
|