Descripteurs de forme basés sur les graphes de voisinage#
Ce notebook démontre comment déterminer les descripteurs de forme des cellules dans le cas où elles ne peuvent pas être segmentées exactement mais où leurs centres peuvent être détectés.
from skimage.measure import regionprops
import numpy as np
import pyclesperanto_prototype as cle
cle.get_device()
<gfx90c on Platform: AMD Accelerated Parallel Processing (2 refs)>
Nous générons une image d’étiquettes de cellules avec des tailles données en x et y et un rapport de taille de 1:1,5.
Supposons que c’est le résultat d’un algorithme de segmentation cellulaire.
cell_size_x = 10
cell_size_y = 15
# generate and show tissue
tissue_labels = cle.artificial_tissue_2d(width=100, height=100, delta_x=cell_size_x, delta_y=cell_size_y, random_sigma_x=1, random_sigma_y=1)
cle.imshow(tissue_labels, labels=True)
Descripteurs de forme classiques : axes mineur et majeur#
Nous pouvons mesurer les axes mineur et majeur de ces cellules en utilisant scikit-image
label_image = cle.pull_zyx(tissue_labels).astype(int)
stats = regionprops(label_image)
avg_minor_axis_length = np.mean([s.minor_axis_length for s in stats])
print("Longueur moyenne de l'axe mineur", avg_minor_axis_length)
avg_major_axis_length = np.mean([s.major_axis_length for s in stats])
print("Longueur moyenne de l'axe majeur", avg_major_axis_length)
Average minor axis length 11.094738115993875
Average major axis length 16.966309163176998
Nous générons maintenant une image où les cellules pourraient être difficiles à segmenter, par exemple une image de membrane.
cell_borders = cle.detect_label_edges(label_image)
convolved_membranes = cle.gaussian_blur(cell_borders, sigma_x=1, sigma_y=2)
noise_level = 3
noise = (np.random.random(convolved_membranes.shape) - 0.5) * cle.mean_of_all_pixels(convolved_membranes) * noise_level
noise = noise.astype(np.float32)
artifical_membrane_image = (convolved_membranes + noise)
cle.imshow(artifical_membrane_image)
Descripteurs de forme basés sur les maillages de voisins#
Dans certains cas, nous ne pouvons pas segmenter correctement les cellules, nous pouvons juste faire une détection de points et visualiser les centres des cellules.
blurred = cle.gaussian_blur(artifical_membrane_image, sigma_x=2, sigma_y=2)
local_minima = cle.detect_minima_box(blurred)
spot_image = cle.label_spots(local_minima)
# we extend the spots a little bit for visualization purposes
spot_image = cle.maximum_sphere(spot_image, radius_x=1, radius_y=1)
cle.imshow(spot_image, labels=True)
À partir d’une telle image de points étiquetés, nous pouvons créer un diagramme de Voronoï, où nous pouvons analyser quelles cellules (points étendus) sont proches les unes des autres.
Le résultat est une approximation de la segmentation cellulaire.
voronoi_diagram_all = cle.extend_labeling_via_voronoi(spot_image)
# exclude labels on image edges
voronoi_diagram = cle.exclude_labels_on_edges(voronoi_diagram_all)
cle.imshow(voronoi_diagram, labels=True)
À partir d’une telle paire d’images de points et de diagramme de Voronoï, nous pouvons déterminer deux matrices, une matrice de contact (également connue sous le nom de matrice de graphe d’adjacence) et une matrice de distance.
touch_matrix = cle.generate_touch_matrix(voronoi_diagram)
# igonore touching the background
cle.set_column(touch_matrix, 0, 0)
centroids = cle.centroids_of_labels(voronoi_diagram)
distance_matrix = cle.generate_distance_matrix(centroids, centroids)
cle.imshow(touch_matrix)
cle.imshow(distance_matrix)
À partir de ces deux matrices, nous pouvons déterminer la distance minimale et maximale entre les centroïdes des objets en contact (cellules) dans l’image de Voronoï. Ce sont les axes mineur et majeur estimés des objets segmentés.
min_distance = cle.minimum_distance_of_touching_neighbors(distance_matrix, touch_matrix)
max_distance = cle.maximum_distance_of_touching_neighbors(distance_matrix, touch_matrix)
print("distance minimale des voisins en contact", cle.mean_of_all_pixels(min_distance))
print("distance maximale des voisins en contact", cle.mean_of_all_pixels(max_distance))
minimum distance of touching neihbors 10.007136855014535
maximum distance of touching neihbors 16.39732325354288
Visualisation des distances#
Enfin, visualisons les distances entre les voisins dans un maillage coloré.
mesh = cle.draw_distance_mesh_between_touching_labels(voronoi_diagram)
cle.imshow(mesh, colorbar=True, colormap="jet")