Mediciones en objetos en imágenes en mosaico#
Para algunas tareas específicas de análisis de imágenes, podría ser posible superar limitaciones como cuando se aplica el etiquetado de componentes conectados.
Por ejemplo, al medir el tamaño de los objetos y si estos objetos tienen un tamaño limitado, no es necesario combinar los resultados intermedios del procesamiento de imágenes en imágenes grandes. Podríamos simplemente medir las propiedades de los objetos para todos los objetos en mosaicos y luego combinar el resultado de la cuantificación.
import numpy as np
import dask
import dask.array as da
from skimage.data import cells3d
from skimage.io import imread
import pyclesperanto_prototype as cle
from pyclesperanto_prototype import imshow
Nuestro punto de partida es nuevamente una imagen binaria que muestra objetos segmentados.
image = imread("../../data/blobs.tif") > 128
imshow(image)
Esta vez, nos gustaría medir el tamaño de los objetos y visualizarlo en una imagen paramétrica. Con fines de demostración, ejecutamos esa operación primero en toda la imagen de ejemplo.
def area_map(image):
"""
Label objects in a binary image and produce a pixel-count-map image.
"""
labels = cle.connected_components_labeling_box(image)
result = cle.pixel_count_map(labels)
return np.asarray(result)
reference = area_map(image)
cle.imshow(reference, colorbar=True)
Si procesamos lo mismo en mosaicos, obtendremos resultados ligeramente incorrectos debido al problema de etiquetado de componentes conectados en mosaicos demostrado anteriormente.
# tile the image
tiles = da.from_array(image, chunks=(128, 128))
# setup the operation we want to apply
procedure = area_map
# setup the tiling
tile_map = da.map_blocks(procedure, tiles)
# compute result
result = tile_map.compute()
# visualize
imshow(result, colorbar=True)
De nuevo, los errores son visibles en el borde y podemos visualizarlos mediante comparación directa:
absolute_error = cle.absolute_difference(result, reference)
cle.imshow(absolute_error, colorbar=True)
Para prevenir este error, necesitamos pensar nuevamente en procesar los mosaicos de la imagen con una superposición. En este ejemplo particular, no estamos ejecutando ninguna operación que tenga en cuenta los píxeles vecinos. Por lo tanto, no podemos estimar la superposición necesaria a partir de tales parámetros. Necesitamos tener en cuenta el tamaño máximo (diámetro) de los objetos. También podríamos hacerlo empíricamente, como antes. Por lo tanto, calculemos primero el error cuadrático medio de los dos resultados de ejemplo anteriores:
cle.mean_squared_error(result, reference)
4338.783956692913
Y a continuación, podemos calcular ese error en un bucle variando el tamaño de superposición usando dask.array.map_overlay mientras procesamos la imagen en mosaicos. Tenga en cuenta que estamos configurando boundary=0 aquí, porque de lo contrario los objetos se extenderían en la imagen binaria y las mediciones de tamaño serían incorrectas.
for overlap_width in range(0, 30, 5):
print("Overlap width", overlap_width)
tile_map = da.map_overlap(procedure, tiles, depth=overlap_width, boundary=0)
result = tile_map.compute()
print("mean squared error", cle.mean_squared_error(result, reference))
print("-----------------------------------")
Overlap width 0
mean squared error 4338.783956692913
-----------------------------------
Overlap width 5
mean squared error 1702.8293553149606
-----------------------------------
Overlap width 10
mean squared error 460.85811392716533
-----------------------------------
Overlap width 15
mean squared error 70.78670952263779
-----------------------------------
Overlap width 20
mean squared error 1.2793891486220472
-----------------------------------
Overlap width 25
mean squared error 0.0
-----------------------------------
La superposición determinada empíricamente donde este error se vuelve 0 es una estimación optimista. Al usar este método en su ejemplo, asegúrese de aplicar una superposición que sea mayor que el valor determinado.
Nota: Las funciones compute e imshow pueden no funcionar en conjuntos de datos grandes ya que las imágenes pueden no caber en la memoria de la computadora. Las estamos usando aquí con fines de demostración.
overlap_width = 30
tile_map = da.map_overlap(procedure, tiles, depth=overlap_width, boundary=0)
result = tile_map.compute()
cle.imshow(tile_map, colorbar=True)