TNI+VO · Exercice de Programmation

EP09_05 — 🟠 Évaluation de segmentation : IoU et Dice pixel par pixel

9.10.5 EP09_05 🟠 Évaluation de segmentation : IoU et Dice pixel par pixel

Le Bloc 2 de la section « Segmentation sémantique avec l’architecture U-Net » définit, en quelques lignes, la fonction iou_mascaras, utilisée pour mesurer la qualité de la ligne de base morphologique classique (lissage + Otsu + ouverture) et, plus loin, celle de la U-Net elle-même après entraînement. Contrairement à l’IoU de l’EP09_04 — calculé sur des boîtes englobantes (régions rectangulaires décrites par quatre nombres) —, l’IoU de segmentation est calculé pixel par pixel : chaque position de l’image est comparée individuellement entre le masque prédit et le masque de référence.

Vous êtes chargé de généraliser cette évaluation, en implémentant non seulement l’IoU pixel par pixel, mais aussi le coefficient de Dice, une autre métrique de chevauchement largement utilisée en segmentation médicale (y compris dans la fonction perda_dice, mentionnée dans le même bloc du chapitre comme base de la fonction de perte utilisée pour entraîner la U-Net).

9.10.5.1 📋 Directives d’implémentation

  1. Entrée : Lire les dimensions \(H \times W\) des masques.

  2. Masque prédit : Lire \(H\) lignes contenant chacune \(W\) valeurs entières (0 ou 1) — par exemple, la sortie d’une U-Net après seuillage à \(0{,}5\) sur la sigmoïde, comme dans le Bloc 4 du chapitre.

  3. Masque de référence : Lire \(H\) lignes supplémentaires avec chacune \(W\) valeurs entières (0 ou 1) — la vérité terrain (ground truth).

  4. Intersection et union : En considérant chaque pixel comme appartenant à l’objet lorsque sa valeur est non nulle, \[ \text{intersection} = \sum_{i,j} \mathbb{1}[P_{ij}=1 \wedge R_{ij}=1], \qquad \text{union} = \sum_{i,j} \mathbb{1}[P_{ij}=1 \vee R_{ij}=1]. \]

  5. IoU pixel par pixel : \[ \text{IoU} = \frac{\text{intersection}}{\text{union}}. \]

  6. Coefficient de Dice : \[ \text{Dice} = \frac{2 \cdot \text{intersection}}{|P| + |R|}, \] où \(|P|\) et \(|R|\) sont le nombre total de pixels d’objet dans chaque masque.

  7. Convention pour les masques vides : si les deux masques ne contiennent aucun pixel d’objet (union \(= 0\) et \(|P|+|R|=0\)), considérez la correspondance comme trivialement parfaite : \(\text{IoU} = \text{Dice} = 1{,}0\).

  8. Sortie : Deux lignes, IoU: X.XXXX et Dice: X.XXXX, chaque valeur avec 4 décimales.

9.10.5.2 📌 Contraintes de calcul

  • Toute valeur non nulle compte comme objet : traitez les valeurs différentes de \(0\) (pas seulement \(1\)) comme appartenant au masque, en répliquant la vérification predita > 0 utilisée dans iou_mascaras au chapitre.
  • Mêmes dimensions : les deux masques ont toujours exactement \(H \times W\) éléments.
  • Convention de vide : appliquez la règle de l’item 7 uniquement lorsque les deux masques sont entièrement vides ; si un seul est vide, l’intersection est \(0\) et l’IoU/Dice résultant sera également \(0\).

9.10.5.3 🧠 Fondement théorique

Élément Rôle dans l’évaluation de segmentation
IoU pixel par pixel Généralise la métrique de l’EP09_04 à des régions de forme arbitraire — pas seulement des rectangles — en comparant le masque prédit et la référence position par position
Coefficient de Dice Métrique liée à l’IoU (toujours \(\text{Dice} \ge \text{IoU}\)), plus sensible aux petites intersections et largement utilisée comme fonction de perte en segmentation (fonction perda_dice du chapitre)
Convention des masques vides Évite la division par zéro et reconnaît que « aucun objet prédit, aucun objet réel » est, par définition, une réussite
Comparaison classique vs. U-Net Le chapitre utilise exactement ce type de métrique pour justifier, numériquement, pourquoi la U-Net surpasse la ligne de base morphologique dans des scénarios à faible contraste

9.10.5.4 🧩 Méthodes de morph.py pouvant aider

  • mm.readImg(h, w, dtype='uint8') — lit directement chaque masque binaire \(h \times w\) depuis l’entrée standard (les valeurs \(0/1\) tiennent parfaitement dans le type entier standard).
  • La fonction iou_mascaras elle-même, définie dans le Bloc 2 de la section U-Net du chapitre (ne fait pas partie de morph.py, mais du code du chapitre), est l’inspiration directe de cet exercice — il vaut la peine de relire ces quelques lignes avant de programmer.
  • Pour une extension optionnelle (non exigée par cet EP), mm.connectedComponents ou mm.label0 (vus dans le contexte de l’analyse des composantes connexes) permettraient de labelliser chaque nodule individuellement et de calculer l’IoU par composante, plutôt que sur le masque entier.

9.10.5.5 📦 Spécification d’entrée et de sortie (VPL)

Entrée :

  • Ligne 1 : Entiers \(H\) et \(W\).
  • \(H\) lignes suivantes : \(W\) valeurs entières (0 ou 1) — masque prédit.
  • \(H\) lignes suivantes : \(W\) valeurs entières (0 ou 1) — masque de référence.

Sortie :

  • Ligne 1 : IoU: X.XXXX.
  • Ligne 2 : Dice: X.XXXX.
Astuce💡 Exemple illustratif

Considérons un masque prédit avec un carré \(2\times2\) de pixels actifs et une référence décalée d’une colonne, se chevauchant sur seulement la moitié de la surface :

Prédit          Référence
0 0 0 0         0 0 0 0
0 1 1 0         0 0 1 1
0 1 1 0         0 0 1 1
0 0 0 0         0 0 0 0

Intersection \(=2\) pixels, union \(=6\) pixels (\(4+4-2\)), donc \(\text{IoU}=2/6\approx0{,}3333\) et \(\text{Dice}=2\cdot2/(4+4)=0{,}5000\) — notez que le Dice est toujours supérieur ou égal à l’IoU pour le même chevauchement.

9.10.5.6 📌 Exemples

Entrée Sortie Observation
4 4
0 0 0 0
0 1 1 0
0 1 1 0
0 0 0 0
0 0 0 0
0 0 1 1
0 0 1 1
0 0 0 0
IoU: 0.3333
Dice: 0.5000
Masques \(4\times4\) avec chevauchement partiel de 2 pixels.
🎮 Simulateur : IoU et Dice pixel par pixel 🟠 Segmentation
Intersection (VP) Prédite uniquement (FP) Référence uniquement (FN) Fond (VN)
5×5
Carré
🔵 Masque prédit
🟡 Masque de référence
🎯 Comparaison visuelle
📊 Calculs et formules
Figure 9.47: Simulador EP09_05: Évaluation de la segmentation — IoU et Dice pixel par pixel
%%writefile EP09_05.py
# Code Python
Overwriting EP09_05.py
TestSuite("EP09_05.py").run()
✔️ EP09_05.cases existe déjà dans casos/
📋 4 cas chargé(s) depuis casos/EP09_05.cases

🔍 Test de Python : EP09_05.py
⚠️ EP09_05.py : fichier vide (moins de 3 lignes). Tests ignorés.