clEsperanto#

clEsperanto es un proyecto entre múltiples ecosistemas de análisis de bioimágenes que tiene como objetivo eliminar las barreras del lenguaje. Está basado en OpenCL, un estándar abierto para programar unidades de procesamiento gráfico (GPUs, y más) y su wrapper en Python pyopencl. Internamente, utiliza kernels de procesamiento originados del proyecto clij.

Ver también

Inicialización de la GPU#

Comenzaremos inicializando y revisando qué GPUs están instaladas:

import pyclesperanto_prototype as cle
import matplotlib.pyplot as plt
import stackview

# list available devices
cle.available_device_names()
['NVIDIA GeForce RTX 3050 Ti Laptop GPU',
 'gfx1035',
 'cupy backend (experimental)']
# select a specific device with only a part of its name
cle.select_device("2080")
C:\Users\haase\mambaforge\envs\bio39\lib\site-packages\pyclesperanto_prototype\_tier0\_device.py:77: UserWarning: No OpenCL device found with 2080 in their name. Using gfx1035 instead.
  warnings.warn(f"No OpenCL device found with {name} in their name. Using {device.name} instead.")
<gfx1035 on Platform: AMD Accelerated Parallel Processing (2 refs)>
# check which device is uses right now
cle.get_device()
<gfx1035 on Platform: AMD Accelerated Parallel Processing (2 refs)>

Procesamiento de imágenes#

Para cargar datos de imagen, usamos scikit-image como de costumbre:

from skimage.io import imread, imshow

image = imread("../../data/blobs.tif")
imshow(image)
<matplotlib.image.AxesImage at 0x206d07ad0a0>
../_images/eb756dc9532e8cdefa98ec3218709d0b49891bc9b5e8c7da3549af18dfb22404.png

La puerta de enlace cle. tiene todos los métodos que necesitas, no tiene subpaquetes:

# noise removal
blurred = cle.gaussian_blur(image, sigma_x=1, sigma_y=1)
blurred
cle._ image
shape(254, 256)
dtypefloat32
size254.0 kB
min10.285456
max248.0
# binarization
binary = cle.threshold_otsu(blurred)
binary
cle._ image
shape(254, 256)
dtypeuint8
size63.5 kB
min0.0
max1.0
# labeling
labels = cle.connected_components_labeling_box(binary)
labels
cle._ image
shape(254, 256)
dtypeuint32
size254.0 kB
min0.0
max62.0
# visualize results
imshow(labels)
C:\Users\haase\mambaforge\envs\bio39\lib\site-packages\skimage\io\_plugins\matplotlib_plugin.py:149: UserWarning: Low image data range; displaying image with stretched contrast.
  lo, hi, cmap = _get_display_range(image)
<matplotlib.image.AxesImage at 0x206d2d6cb80>
../_images/2fa7591f17ba2c94525b5b9fd2ab7d0563100403bb291865860a00720638c8c8.png

stackview también viene con una función imshow, que permite, por ejemplo, mostrar imágenes de etiquetas de manera más conveniente:

stackview.imshow(labels)
../_images/68262d80e6db50806bf9d41a6f283e5b48ae36c9c546d373a24b2b51f3d44603.png

También se pueden determinar los bordes de las etiquetas y superponerlos sobre la imagen.

label_edges = cle.detect_label_edges(labels) * labels

stackview.imshow(image, continue_drawing=True)
stackview.imshow(label_edges, alpha=0.5)
../_images/f4fc37bbd33da42f059fe435421bc13ee57e80ed029ab10b10a2962a141a67bf.png

Por lo tanto, puede tener sentido aumentar la figura y combinar múltiples subgráficos

fig, axs = plt.subplots(1, 2, figsize=(12,12))

# left plot
stackview.imshow(image, plot=axs[0])

# right plot
stackview.imshow(image, alpha=0.5, continue_drawing=True, plot=axs[1])
stackview.imshow(label_edges, labels=True, alpha=0.5, plot=axs[1])
../_images/06339ef6c16f6f0e6987852549376cb5e9ec439f5f7f554ddc3ce530b1d17826.png

Algunas de estas operaciones, por ejemplo voronoi_otsu_labeling son de hecho atajos y combinan una serie de operaciones como el desenfoque gaussiano, el etiquetado de Voronoi y la umbralización de Otsu para pasar directamente de una imagen en bruto a una imagen etiquetada:

labels = cle.voronoi_otsu_labeling(image, spot_sigma=3.5, outline_sigma=1)
labels
cle._ image
shape(254, 256)
dtypeuint32
size254.0 kB
min0.0
max66.0

Además, solo un recordatorio, lee la documentación de los métodos que no hayas usado antes:

print(cle.voronoi_otsu_labeling.__doc__)
Labels objects directly from grey-value images.

    The two sigma parameters allow tuning the segmentation result. Under the hood,
    this filter applies two Gaussian blurs, spot detection, Otsu-thresholding [2] and Voronoi-labeling [3]. The
    thresholded binary image is flooded using the Voronoi tesselation approach starting from the found local maxima.

    Notes
    -----
    * This operation assumes input images are isotropic.

    Parameters
    ----------
    source : Image
        Input grey-value image
    label_image_destination : Image, optional
        Output image
    spot_sigma : float, optional
        controls how close detected cells can be
    outline_sigma : float, optional
        controls how precise segmented objects are outlined.
    
    Returns
    -------
    label_image_destination
    
    Examples
    --------
    >>> import pyclesperanto_prototype as cle
    >>> cle.voronoi_otsu_labeling(source, label_image_destination, 10, 2)
    
    References
    ----------
    .. [1] https://clij.github.io/clij2-docs/reference_voronoiOtsuLabeling
    .. [2] https://ieeexplore.ieee.org/document/4310076
    .. [3] https://en.wikipedia.org/wiki/Voronoi_diagram
    

Interoperabilidad#

En pyclesperanto, las imágenes se manejan en la memoria de acceso aleatorio (RAM) de tu GPU. Si quieres usar otras bibliotecas que procesan imágenes en la GPU, la memoria debe ser transferida de vuelta. Normalmente, esto ocurre de manera transparente para el usuario, por ejemplo, cuando se usa scikit-image para medir las propiedades de las regiones:

from skimage.measure import regionprops

statistics = regionprops(labels)

import numpy as np
np.mean([s.area for s in statistics])
333.77272727272725

Si quieres convertir explícitamente tu imagen, por ejemplo en un arreglo numpy, puedes hacerlo así:

np.asarray(labels)
array([[ 0,  0,  0, ..., 62, 62, 62],
       [ 0,  0,  0, ..., 62, 62, 62],
       [ 0,  0,  0, ..., 62, 62, 62],
       ...,
       [ 0,  0,  0, ...,  0,  0,  0],
       [ 0,  0,  0, ...,  0,  0,  0],
       [ 0,  0,  0, ...,  0,  0,  0]], dtype=uint32)

Gestión de memoria#

En los cuadernos jupyter, las variables se mantienen vivas mientras el kernel del cuaderno esté en ejecución. Por lo tanto, tu GPU puede llenarse de memoria. Así, si ya no necesitas una imagen, elimínala de la memoria usando del. Entonces será eliminada de la memoria de la GPU gracias a la magia de pyopencl.

del image
del blurred
del binary
del labels