Université Bordeaux 1 Master ISV, Image 3D 2013/2014 Segmentation et Analyse d’image - TP 2 Watershed / Ligne de partage des eaux La ligne de partage des eaux (watershed en anglais) constitue un outil puissant pour analyser la topographie d’une image. Elle est utilisée en segmentation d’image, puisqu’elle peut délimiter un ensemble de zones qui forment une partition de l’image originale. Dans ce cadre, la ligne de partage des eaux est en général appliquée à l’image des contours, où les contours forts peuvent être vus comme des crêtes qui séparent des vallées assez plates (les régions homogènes). La Figure 1 donne un exemple de segmentation d’image par watershed. Nous allons mettre en œuvre un algorithme de calcul de la ligne de partage des eaux, proposé par Vincent et Soille (IEEE PAMI, 1991). Cet algorithme utilise le principe de l’immersion pour déterminer les bassins d’écoulement. L’algorithme peut se synthétiser ainsi : 1. L’immersion est progressive. A chaque étape, on considère que tous les pixels de niveau < h ont été traités et on traite le niveau h. On a donc un ensemble de bassins déjà partiellement repérés, ainsi que certains pixels “frontière” (WATERSHED dans le code) qui séparent deux bassins distincts. 2. Les pixels de niveau h sont ensuite soit rattachés à un bassin existant, soit repérés comme étant “frontière”, soit enfin reconnus comme étant un nouveau bassin. La première étape se réalise assez simplement en triant tous les pixels de l’image suivant leur valeur. La deuxième étape est plus délicate car elle nécessite de traiter les pixels dans un certain ordre. a c b d Figure 1 – (a) image originale, (b) image de la norme du gradient calculée par masque de Sobel, (c) ligne de partage des eaux, (d) minima régionaux (en blanc). Expérimentation de l’algorithme L’archive (http ://dept-info.labri.fr/∼vialard/Image3D/src/tp2.tgz) contient : – un répertoire images contenant des images de test – un répertoire bin contenant les fichiers .class d’un plugin ImageJ de calcul de watershed. – un répertoire src contenant les fichiers source du plugin à compléter. Testez le plugin avec les paramètres suivants : Image laBaule_spot laBaule_spot tools tools tools Entrée de l’algorithme gradient gradient gradient gradient gradient 5 25 5 20 40 Refaites les mêmes tests sur les images préalablement traitées par un filtre moyenne puis par un filtre médian. Que constatez-vous ? A quoi sert en pratique le paramètre epsilon, qui permet de considérer des pixels d’altitude proche comme ayant la même altitude ? Est-ce que l’algorithme est sensible au bruit de l’image ? Calcul de la ligne de partage des eaux Les entrées de l’algorithme sont : – une image de nombre flottants (les altitudes des pixels) – un nombre flottant (incertitude sur l’altitude) En sortie, l’algorithme fournit une image d’entiers : chaque pixel contient soit une étiquette correspondant à un bassin, soit WATERSHED s’il sépare deux bassins. Editez la classe Watershed et sa méthode calculeWatershed. Observez bien ce qui est déjà écrit (voir aussi la Figure 2). Les étapes de l’algorithme, déjà écrites ou à compléter, sont les suivantes : 1. Les pixels sont d’abord triés par ordre croissant d’altitude. 2. Ils sont ensuite traités par série : tous ceux entre h et h+ sont considérés d’altitude identique. 3. Ces pixels sont alors MASKés et il faut déterminer à quel bassin ils appartiennent. 4. On commence par traiter les nouveaux pixels MASKés qui touchent déjà un bassin (pixel étiqueté) ou une frontière (pixel WATERSHED). Ils sont à distance 1. Les autres MASKés seront à distance 2, 3, voire plus. Voir (II) dans le code Watershed.java. 5. Ces pixels sont placés dans une file d’attente. Un élément fictif indique la fin de file et donc le passage à des pixels à des distances supérieures. Voir (III) dans le code. 6. Etant donné un pixel dans la file, on peut maintenant le traiter en fonction de son voisinage. Implémentez l’étiquetage du pixel courant. Voir (IV.TODO). Pour ce faire, reprenez les cas possibles (cf. Figure 3). Les points suivants sont importants : – On ne teste que les voisins de distance inférieure à la distance courante (les autres, de même distance que le pixel courant, sont traités en parallèle). – Le calcul se fait en regardant successivement les quatre pixels adjacents : le pixel courant peut donc être réétiqueté différemment plusieurs fois. – Le pixel sera étiqueté soit par un label voisin, soit par WATERSHED. – Il faut aussi déterminer les pixels voisins à distance +1 et les mettre dans la file. A la détection, ils sont de distance nulle et MASKés. 7. La dernière phase de l’algorithme reprend tous les pixels traités, et s’ils ne sont pas étiquetés, leur donne une nouvelle étiquette. Tous les voisins non étiquetés sont étiquetés de même par propagation. Implémentez cet étiquetage des nouveaux bassins. Voir (V. TODO). Reprenez les tests du premier exercice. Fermeture des frontières entre bassins La ligne de partage des eaux telle que calculée par cet algorithme ne crée pas des frontières complètes autour des régions. En effet, les frontières sont placées sur les pixels à égale distance entre deux bassins. Complétez la méthode fermeWatershed pour fermer les frontières après calcul du watershed. 2 UNLABELLED 11 00 00 11 00 11 0 1 2 2 1 2 1 2 MASK (distance) 1 2 WATERSHED 1 111 000 000 111 000 111 000 111 000 111 2 Label0 1 Label1 1 Label2 000 111 11 00 000 111 00 11 00 11 00 11 00 11 00 11 00 11 00 11 00 11 Figure 2 – Illustration d’une étape de l’algorithme. Pour chaque pixel MASKé, les flèches indiquent les seuls voisins pris en compte dans la détermination de son label. (a) légende des étiquettes. (b) traitement des pixels MASKés à distance 1 du bord, (c) traitement des pixels MASKés à distance 2 du bord, (d) fin de l’itération. avant après Impossible 11 00 00 11 000 111 000 111 000 111 11 00 00 11 11 00 00 11 00 11 111 000 00 11 000 111 00 11 00011 111 0011 11 00 11 00 11 00 00 00 00 11 11 00 11 0011 11 0000 11 00 11 00 11 000 00 11 00 111 11 000 111 00 11 00 111 11 000 00 11 Figure 3 – Illustration de l’étiquetage d’un pixel MASKé. La nouvelle étiquette dépend des étiquettes des voisins. Un certain nombre de configurations sont illustrées. Le principe est simple : pour chaque pixel p de l’image, s’il y a un pixel voisin dont le label est inférieur, alors p doit être étiqueté comme “frontière”. Est-ce que cette technique de fermeture est indépendante d’une rotation ou symétrie de l’image ? Affichage des bassins selon la moyenne Proposez une autre façon d’afficher les bassins, non plus avec une couleur aléatoire, mais avec le niveau de gris moyen de la région correspondante dans l’image originale. Voyez-vous un intérêt autre que juste visuel à cette transformation ? Pour aller plus loin... L’algorithme produisant souvent beaucoup de petites régions peu significatives, écrivez une méthode de Watershed qui agrège les petites régions aux régions voisines, en privilégiant la ligne de partage des eaux la plus basse. La façon la plus simple de procéder est de reprendre l’algorithme de calculeWatershed et de le modifier ainsi : – Il faut un tableau d’indirection de labels qui permet de réétiqueter les labels existants. – Il faut mémoriser au fur et à mesure la taille de chaque région. – Lorsque deux régions se touchent, on a un comportement différent si une des deux régions est d’une taille inférieure à un seuil donné en paramètre. Dans ce cas-là, on indique que les deux bassins sont identiques en mettant à jour le tableau d’indirection de labels. Une autre méthode pour limiter le nombre de petites régions est la simplification par marquage. Elle est très similaire à la méthode précédente, sauf que c’est l’utilisateur qui marque des pixels correspondant à des bassins. Les bassins qui ne contiennent pas de marque s’absorbent les uns les autres. Si un bassin contient une marque, il absorbe les bassins qui n’en ont pas. Si deux bassins qui contiennent chacun une marque se touchent, alors dans ce cas-là seulement, on construit la ligne de partage des eaux entre les deux. 3