Medir distancia a una línea central#
Una pregunta común es cómo determinar las distancias de puntos al centro de un objeto segmentado. Para esto podemos esqueletizar el objeto, producir un mapa de distancia y leer las intensidades del mapa de distancia en los puntos dados para determinar su distancia al esqueleto / línea central.
Ver también:
https://scikit-image.org/docs/stable/auto_examples/edges/plot_skeleton.html
https://examples.itk.org/src/filtering/distancemap/maurerdistancemapofbinary/documentation
from skimage.io import imread
import napari_segment_blobs_and_things_with_membranes as nsbatwm
import napari_simpleitk_image_processing as nsitk
import numpy as np
import stackview
import pyclesperanto_prototype as cle
Punto de partida: una imagen binaria#
Comenzamos usando una imagen binaria que se parece a un brazo.
binary_arm = imread("../../data/binary_arm.tif")
stackview.insight(binary_arm)
|
|
|
Además, continuamos con una lista de coordenadas en formato X/Y:
coordinates_xy = np.asarray([
[70, 80],
[70, 70],
[70, 60]]).T
A continuación, producimos una imagen de etiquetas donde las coordenadas dadas están etiquetadas. La primera coordenada (índice=0 en la lista) será etiquetada con 1, la segunda con 2, y así sucesivamente. Los píxeles de fondo son 0. Usamos esta imagen de etiquetas para visualización y más adelante, también usaremos esta imagen para hacer la medición.
# draw the coordinates into an image; for visualization purposes
blank_image = cle.create((binary_arm.shape))
labeled_spots = coordinate_visualization = cle.pointlist_to_labelled_spots(coordinates_xy, blank_image)
# show the labeled pixels on top of the binary image
cle.imshow(binary_arm, continue_drawing=True, max_display_intensity=1)
cle.imshow(labeled_spots, labels=True, alpha=0.6)
Pre-procesamiento#
Antes de poder esqueletizar la imagen, necesitamos llenar los agujeros negros en el área blanca.
filled_holes = nsitk.binary_fill_holes(binary_arm)
filled_holes
|
|
n-sitk made image
|
Esqueletización#
El esqueleto de una imagen binaria es una línea delgada en el centro de las áreas blancas.
skeleton = nsbatwm.skeletonize(filled_holes)
skeleton
<__array_function__ internals>:200: RuntimeWarning: Converting input from bool to <class 'numpy.uint8'> for compatibility.
|
|
nsbatwm made image
|
Mapa de distancia#
A continuación, dibujamos un Mapa de Distancia de Maurer Firmado. Los mapas de distancia son imágenes donde la intensidad representa la distancia de un píxel al píxel blanco más cercano en la imagen binaria de la que se generó el mapa de distancia.
distance_map = nsitk.signed_maurer_distance_map(skeleton)
distance_map
|
|
n-sitk made image
|
Usando stackview.picker podemos pasar el mouse sobre la imagen y leer las intensidades. Esto solo funciona en un entorno tipo Jupyter.
stackview.picker(distance_map, zoom_factor=3)
Mediciones#
Ahora podemos leer la intensidad en el mapa de distancia en las ubicaciones dadas de los puntos etiquetados.
values_at_positions = cle.read_intensities_from_positions(coordinates_xy, distance_map)
np.asarray(values_at_positions)
array([[-15.033297 , -5.0990195, -4. ]], dtype=float32)
Ejercicio#
Utiliza el mapa de distancia en la imagen binary_arm para determinar la distancia de los tres puntos desde el borde del brazo, en lugar de la línea central.