Descriptores de forma basados en grafos de vecindad#
Este cuaderno demuestra cómo determinar descriptores de forma de células en caso de que no puedan ser segmentadas exactamente pero sus centros puedan ser detectados.
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)>
Generamos una imagen de etiquetas de células con tamaños dados en x e y y una relación de tamaño de 1:1.5.
Asumamos que este es el resultado de algún algoritmo de segmentación celular.
cell_size_x = 10
cell_size_y = 15
# generar y mostrar tejido
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)
Descriptores de forma clásicos: eje menor y mayor#
Podemos medir el eje menor y mayor de esas células usando 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("Longitud promedio del eje menor", avg_minor_axis_length)
avg_major_axis_length = np.mean([s.major_axis_length for s in stats])
print("Longitud promedio del eje mayor", avg_major_axis_length)
Average minor axis length 11.094738115993875
Average major axis length 16.966309163176998
Ahora generamos una imagen donde las células pueden ser difíciles de segmentar, por ejemplo, una imagen de membrana.
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)
Descriptores de forma basados en mallas de vecinos#
En algunos casos, no podemos segmentar las células adecuadamente, solo podemos hacer detección de puntos y visualizar los centros de las células.
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)
# extendemos los puntos un poco para propósitos de visualización
spot_image = cle.maximum_sphere(spot_image, radius_x=1, radius_y=1)
cle.imshow(spot_image, labels=True)
A partir de tal imagen de puntos etiquetados, podemos hacer un diagrama de Voronoi, donde podemos analizar qué células (puntos expandidos) están cerca unas de otras.
El resultado es una aproximación de la segmentación celular.
voronoi_diagram_all = cle.extend_labeling_via_voronoi(spot_image)
# excluir etiquetas en los bordes de la imagen
voronoi_diagram = cle.exclude_labels_on_edges(voronoi_diagram_all)
cle.imshow(voronoi_diagram, labels=True)
A partir de tal par de imágenes de puntos y diagrama de Voronoi, podemos determinar dos matrices, una matriz de contacto (también conocida como matriz de grafo de adyacencia) y una matriz de distancia.
touch_matrix = cle.generate_touch_matrix(voronoi_diagram)
# ignorar el contacto con el fondo
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)
A partir de estas dos matrices, podemos determinar la distancia mínima y máxima entre centroides de objetos en contacto (células) en la imagen de Voronoi. Estos son los ejes menor y mayor estimados de los objetos segmentados.
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("distancia mínima de vecinos en contacto", cle.mean_of_all_pixels(min_distance))
print("distancia máxima de vecinos en contacto", cle.mean_of_all_pixels(max_distance))
minimum distance of touching neihbors 10.007136855014535
maximum distance of touching neihbors 16.39732325354288
Visualización de distancias#
Finalmente, visualicemos las distancias entre vecinos en una malla coloreada.
mesh = cle.draw_distance_mesh_between_touching_labels(voronoi_diagram)
cle.imshow(mesh, colorbar=True, colormap="jet")