Detección de máximos locales#

Para detectar máximos locales, píxeles rodeados por píxeles con menor intensidad, podemos usar algunas funciones en scikit-image y clesperanto.

Ver también

from skimage.feature import peak_local_max
import pyclesperanto_prototype as cle
from skimage.io import imread, imshow
from skimage.filters import gaussian 
import matplotlib.pyplot as plt

Comenzamos cargando una imagen y recortando una región con fines de demostración. Utilizamos el conjunto de imágenes BBBC007v1 versión 1 (Jones et al., Proc. ICCV Workshop on Computer Vision for Biomedical Image Applications, 2005), disponible en la Broad Bioimage Benchmark Collection [Ljosa et al., Nature Methods, 2012].

image = imread("../../data/BBBC007_batch/A9 p7d.tif")[-100:, 0:100]

cle.imshow(image)
../_images/8641a082f73416921fa012245d92e7dcb078bcb651b843865b416a1a714e51e0.png

Preprocesamiento#

Un paso común de preprocesamiento antes de detectar máximos es desenfocar la imagen. Esto tiene sentido para evitar detectar máximos que son solo variaciones de intensidad resultantes del ruido.

preprocessed = gaussian(image, sigma=2, preserve_range=True)

cle.imshow(preprocessed)
../_images/a1fb76dec30384ba824f283d6040b30910372248319637e4af2d3cc6fb41ee32.png

peak_local_max#

La función peak_local_max permite detectar máximos que tienen una intensidad mayor que los píxeles circundantes y otros máximos según un umbral definido.

coordinates = peak_local_max(preprocessed, threshold_abs=5)
coordinates
array([[23, 85],
       [11, 29],
       [41, 40],
       [88, 34],
       [72, 83],
       [69, 89],
       [31, 72],
       [75, 16],
       [80, 22],
       [ 6, 56]], dtype=int64)

Estas coordenadas se pueden visualizar utilizando la función plot de matplotlib.

cle.imshow(preprocessed, continue_drawing=True)
plt.plot(coordinates[:, 1], coordinates[:, 0], 'r.')
[<matplotlib.lines.Line2D at 0x2309908fbb0>]
../_images/6eabc8dfa98723116061ddb967031bf8ff8fb0b6e38bfc0a30276647794d298d.png

Si se detectan demasiados máximos, se pueden modificar los resultados cambiando el parámetro sigma del desenfoque gaussiano arriba o cambiando el umbral pasado a la función peak_local_max.

detect_maxima_box#

La función peak_local_max tiende a tardar mucho tiempo, por ejemplo, al procesar datos de imágenes 3D grandes. Por lo tanto, se introducirá una alternativa: el detect_maxima_box de clesperanto es un filtro de imagen que establece píxeles en el valor 1 en caso de que los píxeles circundantes tengan menor intensidad. Normalmente funciona rápido también en datos de imágenes 3D grandes.

local_maxima_image = cle.detect_maxima_box(preprocessed)
local_maxima_image
cle._ image
shape(100, 100)
dtypeuint8
size9.8 kB
min0.0
max1.0

Obviamente, resulta en una imagen binaria. Esta imagen binaria se puede convertir en una imagen etiquetada numerando individualmente los puntos con diferentes números. De esta imagen etiquetada, podemos eliminar los máximos detectados en los bordes de la imagen, lo que podría ser útil en este caso.

all_labeled_spots = cle.label_spots(local_maxima_image)

labeled_spots = cle.exclude_labels_on_edges(all_labeled_spots)
labeled_spots
cle._ image
shape(100, 100)
dtypeuint32
size39.1 kB
min0.0
max11.0

Para visualizar estos puntos en la imagen original, podría tener sentido aumentar el tamaño de los puntos, solo con fines de visualización.

label_visualization = cle.dilate_labels(labeled_spots, radius=3)

cle.imshow(preprocessed, continue_drawing=True)
cle.imshow(label_visualization, labels=True, alpha=0.5)
../_images/8458205f2922ebc84185e00c56daf9cba55b7592be2b3208a0e9502710cf4c43.png

En la parte inferior central de esta imagen, ahora vemos un máximo local que se ha detectado en el fondo. Podemos eliminar esos máximos en regiones de menor intensidad mediante un umbral.

binary_image = cle.threshold_otsu(preprocessed)
binary_image
cle._ image
shape(100, 100)
dtypeuint8
size9.8 kB
min0.0
max1.0

Ahora podemos excluir etiquetas de la imagen de puntos donde la intensidad en la imagen binaria no está dentro del rango [0..1].

final_spots = cle.exclude_labels_with_map_values_out_of_range(
    binary_image,
    labeled_spots,
    minimum_value_range=1,
    maximum_value_range=1
)
final_spots
cle._ image
shape(100, 100)
dtypeuint32
size39.1 kB
min0.0
max10.0

Luego podemos visualizar los puntos nuevamente utilizando la estrategia introducida anteriormente, pero esta vez en la imagen original.

label_visualization2 = cle.dilate_labels(final_spots, radius=3)

cle.imshow(image, continue_drawing=True)
cle.imshow(label_visualization2, labels=True, alpha=0.5)
../_images/ae780bf69815d2f1e8a6c74bf226ae08899765e680ce393270c28a47db834cb9.png