Scénario : Comparaison de différentes implémentations du même algorithme de seuillage#

Dans ce notebook, nous allons comparer différentes implémentations du même algorithme. Comme exemple, nous sélectionnons la méthode d’Otsu pour le seuillage binaire en combinaison avec l’étiquetage des composantes connexes. L’algorithme a été publié il y a plus de 40 ans et on pourrait supposer que toutes les implémentations courantes de cet algorithme montrent des résultats identiques.

Voir aussi#

from skimage.io import imread, imshow, imsave
from skimage.filters import threshold_otsu
from skimage.measure import label
from skimage.color import label2rgb

Implémentation 1 : ImageJ#

Comme première implémentation, nous examinons ImageJ. Nous l’utiliserons dans le cadre de la distribution Fiji. Le code Macro ImageJ suivant ouvre “blobs.tif”, le seuille en utilisant la méthode d’Otsu et applique l’étiquetage des composantes connexes. L’image étiquetée résultante est enregistrée sur le disque. Vous pouvez exécuter ce script dans l’éditeur de scripts de Fiji en cliquant sur File > New > Script.

Note : Lors de l’exécution de ce script, vous devez adapter le chemin des données d’image pour qu’il fonctionne sur votre ordinateur.

with open('blobs_segmentation_imagej.ijm') as f:
    print(f.read())
open("C:/structure/code/clesperanto_SIMposium/blobs.tif");

// binarization
setAutoThreshold("Otsu dark");
setOption("BlackBackground", true);
run("Convert to Mask");

// Connected component labeling + measurement
run("Analyze Particles...", "  show=[Count Masks] ");

// Result visualization
run("glasbey on dark");

// Save results
saveAs("Tiff", "C:/structure/code/clesperanto_SIMposium/blobs_labels_imagej.tif");

Le résultat ressemble alors à ceci :

imagej_label_image = imread("blobs_labels_imagej.tif")
visualization = label2rgb(imagej_label_image, bg_label=0)
imshow(visualization)
<matplotlib.image.AxesImage at 0x1d290a79520>
../_images/274cd5c9d29a0d56ef587d5388b15a01098442deaaae0bc67c53f90d483b63f9.png

Implémentation 2 : scikit-image#

Comme deuxième implémentation, nous utiliserons scikit-image. Comme il peut être utilisé à partir de notebooks Jupyter, nous pouvons également examiner de près le flux de travail.

Nous commençons par charger et visualiser l’image brute des blobs.

blobs_image = imread("blobs.tif")
imshow(blobs_image, cmap="Greys_r")
C:\Users\rober\miniconda3\envs\bio_39\lib\site-packages\skimage\io\_plugins\matplotlib_plugin.py:150: UserWarning: Float image out of standard range; displaying image with stretched contrast.
  lo, hi, cmap = _get_display_range(image)
<matplotlib.image.AxesImage at 0x1d290cfd7c0>
../_images/8615d0d6587b65fbb39ad4e627fd8475dd7f2343dcdf7647aeda0f1e24d4e092.png

La méthode threshold_otsu est ensuite utilisée pour binariser l’image.

# déterminer le seuil
threshold = threshold_otsu(blobs_image)

# appliquer le seuil
binary_image = blobs_image > threshold

imshow(binary_image)
<matplotlib.image.AxesImage at 0x1d290f67280>
../_images/d912d7acff68e20a54b7cdec9b1c9f50c7c341d650f6e3cffd287839452c4638.png

Pour l’étiquetage des composantes connexes, nous utilisons la méthode label. La visualisation de l’image étiquetée est produite en utilisant la méthode label2rgb.

# étiquetage des composantes connexes
skimage_label_image = label(binary_image)

# visualiser en couleurs
visualization = label2rgb(skimage_label_image, bg_label=0)
imshow(visualization)
<matplotlib.image.AxesImage at 0x1d290d2f940>
../_images/aa39527ccd2e88578b56f997602c2e61f6202049925bd1045e7c872d01b815ff.png

Pour comparer les images plus tard, nous enregistrons également celle-ci sur le disque.

imsave("blobs_labels_skimage.tif", skimage_label_image)
C:\Users\rober\AppData\Local\Temp\ipykernel_6744\179771585.py:1: UserWarning: blobs_labels_skimage.tif is a low contrast image
  imsave("blobs_labels_skimage.tif", skimage_label_image)

Implémentation 3 : clesperanto / python#

La troisième implémentation du même flux de travail s’exécute également à partir de python et utilise pyclesperanto.

Note : Lors de l’exécution de ce script, vous devez adapter le chemin des données d’image pour qu’il fonctionne sur votre ordinateur.

import pyclesperanto_prototype as cle

blobs_image = cle.imread("C:/structure/code/clesperanto_SIMposium/blobs.tif")

cle.imshow(blobs_image, "Blobs", False, 0, 255)

# Seuil Otsu
binary_image = cle.create_like(blobs_image)
cle.threshold_otsu(blobs_image, binary_image)

cle.imshow(binary_image, "Seuil Otsu de l'image CLIJ2 de blobs.gif", False, 0.0, 1.0)

# Étiquetage des composantes connexes Box
label_image = cle.create_like(binary_image)
cle.connected_components_labeling_box(binary_image, label_image)

cle.imshow(label_image, "Étiquetage des composantes connexes Box du seuil Otsu de l'image CLIJ2 de blobs.gif", True, 0.0, 64.0)
../_images/07f150782728e957fcf976380051de87c0faa3adbc2c7ade8b12da32f107ee1d.png ../_images/aac24fde3fd260040b5033ca92c02ff51dae5ae320de2449b8e8e86ef339dc9d.png ../_images/177acdc0fce60609e9cc9d1df01ec420b31863a72853b11ca38319ae2e1f8e5d.png

Nous enregistrerons également cette image pour une comparaison ultérieure.

imsave("blobs_labels_clesperanto_python.tif", label_image)

Implémentation 4 : clesperanto / Jython#

La quatrième implémentation utilise clesperanto dans Fiji. Pour faire fonctionner ce script dans Fiji, veuillez activer les sites de mise à jour clij, clij2 et clijx-assistant dans votre Fiji. Vous remarquerez peut-être que ce script est identique au précédent. Seule la sauvegarde du résultat fonctionne différemment.

Note : Lors de l’exécution de ce script, vous devez adapter le chemin des données d’image pour qu’il fonctionne sur votre ordinateur.

with open('blobs_segmentation_clesperanto.py') as f:
    print(f.read())
# To make this script run in Fiji, please activate the clij, clij2
# and clijx-assistant update sites in your Fiji. 
# Read more: 
# https://clij.github.io/
# 
# To make this script run in python, install pyclesperanto_prototype:
# conda install -c conda-forge pyopencl
# pip install pyclesperanto_prototype
# Read more: 
# https://clesperanto.net
# 
import pyclesperanto_prototype as cle

blobs_image = cle.imread("C:/structure/code/clesperanto_SIMposium/blobs.tif")

cle.imshow(blobs_image, "Blobs", False, 0, 255)

# Threshold Otsu
binary_image = cle.create_like(blobs_image)
cle.threshold_otsu(blobs_image, binary_image)

cle.imshow(binary_image, "Threshold Otsu of CLIJ2 Image of blobs.gif", False, 0.0, 1.0)

# Connected Components Labeling Box
label_image = cle.create_like(binary_image)
cle.connected_components_labeling_box(binary_image, label_image)

cle.imshow(label_image, "Connected Components Labeling Box of Threshold Otsu of CLIJ2 Image of blobs.gif", True, 0.0, 64.0)

# The following code is ImageJ specific. If you run this code from 
# Python, consider replacing this part with skimage.io.imsave
from ij import IJ
IJ.saveAs("tif","C:/structure/code/clesperanto_SIMposium/blobs_labels_clesperanto_imagej.tif");

Nous examinerons également le résultat de ce flux de travail :

imagej_label_image = imread("blobs_labels_clesperanto_imagej.tif")
visualization = label2rgb(imagej_label_image, bg_label=0)
imshow(visualization)
<matplotlib.image.AxesImage at 0x1d291513a90>
../_images/aa39527ccd2e88578b56f997602c2e61f6202049925bd1045e7c872d01b815ff.png