Seuillage#

Le seuillage est une technique de segmentation d’image. Elle sépare une image à canal unique donnée (ou pile) en deux régions : les pixels dont l’intensité est inférieure à un seuil donné, également appelé “arrière-plan”, et les pixels dont l’intensité est supérieure à un seuil donné, “premier plan”. Typiquement, ces algorithmes produisent des images binaires où l’intensité de l’arrière-plan est 0 et l’intensité du premier plan est 1. Lors de l’application de tels algorithmes dans ImageJ, les pixels du premier plan sont 255. Dans scikit-image, les pixels d’arrière-plan sont False et les pixels de premier plan sont True.

Voir aussi

from skimage.io import imread
from pyclesperanto_prototype import imshow
import pyclesperanto_prototype as cle

from skimage import filters
from skimage.filters import try_all_threshold
from matplotlib import pyplot as plt
import napari_simpleitk_image_processing as nsitk
image = imread("../../data/blobs.tif")
imshow(image)
../_images/697332ed931701bd777704b279b47e121b548544b81f7a635c3783b21c04fb53.png

Segmentation d’image par seuillage#

L’opération threshold_otsu, également connue sous le nom de méthode d’Otsu (Otsu et al., IEEE Transactions on Systems, Man, and Cybernetics, Vol. 9 (1), 1979), fournit un nombre - le seuil à appliquer.

threshold = filters.threshold_otsu(image)

Lors de l’utilisation de méthodes telles que le seuillage dans les notebooks, il est recommandé d’imprimer le résultat pour voir ce qu’il retourne réellement. Ici, nous utilisons la méthode de scikit-image, qui renvoie le seuil qui est appliqué. L’impression de ce seuil peut être utile plus tard lors de la reproduction du flux de travail, également si d’autres veulent appliquer le même seuil à l’ensemble de données dans d’autres logiciels.

threshold
120

En utilisant des tableaux numpy, nous pouvons appliquer le seuil en utilisant l’opérateur >=. Le résultat sera une image binaire.

binary_image = image >= threshold

imshow(binary_image)
../_images/a7b2159f4f800a1618c3d6082c124079d4f7e3116111a1a4a4a67982e4eecc1e.png

Nous pouvons également déterminer dans quel type l’image binaire est traitée en imprimant le minimum et le maximum de l’image :

binary_image.max()
True
binary_image.min()
False

Comme montré précédemment, matplotlib nous permet de dessiner un contour sur une image visualisée à l’aide de imshow en utilisant la commande contour.

# créer un nouveau graphique
fig, axes = plt.subplots(1,1)

# ajouter deux images
axes.imshow(image, cmap=plt.cm.gray)
axes.contour(binary_image, [0.5], linewidths=1.2, colors='r')
<matplotlib.contour.QuadContourSet at 0x2b57076dc70>
../_images/06c7022a7454d1160b496fab99037089bf65b12b028c885551cc71daf820b4ae.png

Il existe une liste d’algorithmes de seuillage disponibles. Il est possible de les appliquer tous à vos données et de voir les différences :

fig, ax = try_all_threshold(image, figsize=(10, 8), verbose=False)
plt.show()
../_images/a5bde9d6498b8293b645bd6971e1c424b09bc31486fc161743a8bd2a4341cf99.png

Seuillage utilisant pyclesperanto#

De plus, d’autres bibliothèques telles que pyclesperanto offrent également des algorithmes de seuillage. L’implémentation ici ne renvoie pas le seuil, elle renvoie directement l’image binaire.

binary_image2 = cle.threshold_otsu(image)
imshow(binary_image2)
../_images/aac24fde3fd260040b5033ca92c02ff51dae5ae320de2449b8e8e86ef339dc9d.png

Ici, nous pouvons également voir que différentes bibliothèques stockent les images binaires de différentes manières. pyclesperanto, par exemple, stocke les pixels positifs dans les images binaires non pas comme True mais avec un 1 à la place :

binary_image2.max()
1.0
binary_image2.min()
0.0

Seuillage utilisant SimpleITK#

SimpleITK propose également des algorithmes de seuillage qui peuvent être trouvés dans la liste des filtres. Pour faciliter le script, nous utilisons ici napari-simpleitk-image-processing, un plugin napari scriptable qui offre certaines fonctions SimpleITK de manière plus accessible. Nous pouvons programmer une petite boucle for qui essaie tous les algorithmes de seuillage dans SimpleITK et nous montre les résultats :

threshold_algorithms = [
    nsitk.threshold_huang,
    nsitk.threshold_intermodes,
    nsitk.threshold_isodata,
    nsitk.threshold_kittler_illingworth,
    nsitk.threshold_li,
    nsitk.threshold_maximum_entropy,
    nsitk.threshold_moments,
    nsitk.threshold_otsu,
    nsitk.threshold_renyi_entropy,
    nsitk.threshold_shanbhag,
    nsitk.threshold_triangle,
    nsitk.threshold_yen
]

for algorithm in threshold_algorithms:
    # afficher le nom de l'algorithme au-dessus de l'image
    print(algorithm.__name__)
    
    # binariser l'image en utilisant l'algorithme donné
    binary_image = algorithm(image)
    
    # montrer le résultat de la segmentation
    imshow(binary_image)
threshold_huang
../_images/45e3c8efd769b88b4fc58e4d5c1a50a912d9366ec57f499833c7d4818a16d68f.png
threshold_intermodes
../_images/474585bfc41a7150477a90c9ae4f2ce918a7ed0041e2e5f2eea18e8ace4ae1bb.png
threshold_isodata
../_images/474585bfc41a7150477a90c9ae4f2ce918a7ed0041e2e5f2eea18e8ace4ae1bb.png
threshold_kittler_illingworth
../_images/8d4c59070474247eb02c19ca4d21208dca15778cc0c5e13fadd3e195e8885ce0.png
threshold_li
../_images/ea3d20faef42e8488598e1c914b90d031aefa3b733b82e7d5690f7cbfac67525.png
threshold_maximum_entropy
../_images/a7b2159f4f800a1618c3d6082c124079d4f7e3116111a1a4a4a67982e4eecc1e.png
threshold_moments
../_images/474585bfc41a7150477a90c9ae4f2ce918a7ed0041e2e5f2eea18e8ace4ae1bb.png
threshold_otsu
../_images/aac24fde3fd260040b5033ca92c02ff51dae5ae320de2449b8e8e86ef339dc9d.png
threshold_renyi_entropy
../_images/fccedafce8680667fc01673c4f353031a8b0ce3a2762337531c13b06b405af7e.png
threshold_shanbhag
../_images/507204442c9b905ad28921ef50996a9879695302aaa3686ab31ef89b2579de14.png
threshold_triangle
../_images/aac24fde3fd260040b5033ca92c02ff51dae5ae320de2449b8e8e86ef339dc9d.png
threshold_yen
../_images/134aa11339889cf89aba337af18d894502fe56f28ac0dc73bc0e4d0d8af43abe.png

Exercice#

Segmentez blobs.tif en utilisant l’algorithme de Yen. Utilisez matplotlib pour dessiner un contour vert des objets segmentés autour des régions sur l’image originale.

Segmentez l’image en utilisant un seuil calculé selon cette équation :

threshold = mean + 2 * standard_deviation

Visualisez la segmentation résultante avec un contour rouge sur l’image originale et le contour vert de ci-dessus.

Alternativement, mettez les deux résultats de segmentation dans napari et comparez-les visuellement.