Optimisation des paramètres pour la segmentation cellulaire basée sur l’image de la membrane#

Les flux de travail pour segmenter les cellules à partir d’images de coloration membranaire sont souvent difficiles à optimiser. Dans ce notebook, nous démontrons comment optimiser automatiquement l’algorithme de ligne de partage des eaux avec graines, une approche courante pour ce type de données d’image.

from napari_workflow_optimizer import JaccardLabelImageOptimizer, Workflow

from skimage.io import imread
import napari_segment_blobs_and_things_with_membranes as nsbatwm
import pyclesperanto_prototype as cle
import matplotlib.pyplot as plt
from the_segmentation_game.metrics import jaccard_index_sparse

Nous mettons en place un flux de travail et insérons une seule opération, Ligne de partage des eaux avec graines utilisant les minima locaux comme points de départ en utilisant le plugin Napari napari-segment-blobs-and-things-with-membranes. L’algorithme a deux paramètres : spot_sigma pour ajuster la proximité des points de départ et outline_sigma pour ajuster la précision de la segmentation des membranes.

w = Workflow()
w.set("labeled", # result image name
      nsbatwm.thresholded_local_minima_seeded_watershed, # operation
      "input", spot_sigma=2, outline_sigma=2) # parameters
# image data source: scikit-image cells3d example, slice 28
w.set("input", imread("../../data/membranes_2d.tif"))
input_image = w.get("input")
cle.imshow(input_image)
../_images/e582bd9aaa1d965ac4bbf1c6dc70e9c071f0818c0cfc99ea62e7e963029484a6.png

Nous produisons un premier résultat de segmentation qui est sur-segmenté, il y a évidemment trop de cellules trouvées.

result = w.get("labeled")
cle.imshow(result, labels=True)
../_images/94cbfdd60d9e0413d52cad0a1633de52542aa84530ed4b3fb916eeeb3a0855bb.png

Pour donner à l’algorithme de segmentation une vérité terrain à laquelle comparer les résultats de segmentation, nous utilisons cette image d’annotation éparse. Il suffit généralement d’annoter avec précision quelques cellules d’exemple. Il vaut mieux passer du temps à faire de bonnes segmentations plutôt que d’en dessiner beaucoup.

ground_truth = imread("../../data/membranes_2d_sparse_labels.tif")
cle.imshow(ground_truth, labels=True)
../_images/9db50b653fefde0c26cfabf08d8f73b6e8a880aad8a14aaf0cebcdce1fc1342e.png

Nous pouvons ensuite initialiser le JaccardLabelImageOptimizer. Juste pour tester, nous inspectons le point de départ actuel pour l’optimisation.

jlio = JaccardLabelImageOptimizer(w)
jlio.get_numeric_parameters()
[2, 2, 500]

Nous lançons ensuite l’optimisation et affichons ensuite l’ensemble des paramètres optimisés.

best_param = jlio.optimize("labeled", ground_truth, maxiter=100)
best_param
array([  2.34307473,   5.6861856 , -74.78749191])

Nous pouvons également demander à l’optimiseur de définir ces paramètres pour nous et inspecter l’image étiquetée résultante.

jlio.set_numeric_parameters(best_param)
cle.imshow(w.get("labeled"), labels=True)
../_images/85473129a1e7a7ea7e18a6c348231691b1ff249ea3ce6aecb9e2c2b70cc179c4.png

La qualité de cette image peut être mesurée en faisant la moyenne de l’indice de Jaccard des trois objets de vérité terrain. La bibliothèque The Segmentation Game dispose d’une fonction pour cela.

jaccard_index_sparse(ground_truth, w.get("labeled"))
0.8300891581238193

Parfois, le résultat n’est pas parfait et nous pouvons vouloir modifier un paramètre et voir si le résultat peut être amélioré.

new_starting_point = best_param.copy()
new_starting_point[0] = 8

new_starting_point
array([  8.        ,   5.6861856 , -74.78749191])
jlio2 = JaccardLabelImageOptimizer(w)
jlio2.set_numeric_parameters(new_starting_point)
cle.imshow(w.get("labeled"), labels=True)
../_images/1af543a541e502ab71e23fa598db3fdce5e138f7e7e8044945fa209c9839631e.png

Nous pouvons alors lancer une deuxième tentative.

best_param = jlio.optimize("labeled", ground_truth, maxiter=100)
best_param
array([  9.50775939,   1.39446381, -83.9132378 ])
jlio.set_numeric_parameters(best_param)
cle.imshow(w.get("labeled"), labels=True)
../_images/38c6a0a6aa934ecea8c6ee139e0f341375e2a41ff16f565e519997e3d335ae87.png
jaccard_index_sparse(ground_truth, w.get("labeled"))
0.8905848327576197