Optimizar algoritmos de segmentación#

El plugin de Napari napari-workflow-optimizer permite optimizar flujos de trabajo de segmentación de imágenes de una manera conveniente.

from napari_workflow_optimizer import JaccardLabelImageOptimizer, Workflow

from skimage.io import imread
import pyclesperanto_prototype as cle
import matplotlib.pyplot as plt

Para usar el optimizador, necesitamos definir nuestro flujo de trabajo utilizando un objeto Workflow. Funciona como un diccionario con nombres de imágenes como palabras clave y una lista de operaciones y parámetros como valores. La infraestructura subyacente se basa en gráficos dask.

w = Workflow()
# define background subtraction
w.set("blurred", cle.gaussian_blur, "input", sigma_x=5, sigma_y=5)
# define segmentation
w.set("binarized", cle.threshold_otsu, "blurred")
w.set("labeled", cle.label, "binarized")

Estos flujos de trabajo se pueden explorar. Por ejemplo, podemos leer de él qué parámetros de imagen se necesitan para empezar.

w.roots()
['input']

También podemos determinar cuáles son las imágenes resultantes del flujo de trabajo.

w.leafs()
['labeled']

Después de establecer las entradas, podemos pedirle al flujo de trabajo que calcule los resultados.

w.set("input", imread("../../data/blobs.tif"))
result = w.get("labeled")

cle.imshow(result, labels=True)
../_images/cab4e38e044535463178fcf1e62cd36e32965a28fc1ce952db31796b70694b0d.png

Para la optimización de tal flujo de trabajo, necesitamos una imagen de anotación de verdad fundamental. Una anotación dispersa de algunos objetos es suficiente para esto.

ground_truth = imread("../../data/blobs_sparse_labels.tif")
cle.imshow(ground_truth, labels=True)
../_images/6d517202339c1dd6f59a9e24fd84fc8fd2f0acd0d2aba8012dd49289052ea53f.png

El JaccardLabelImageOptimizer consume un flujo de trabajo y puede optimizar parámetros con respecto a una verdad fundamental dispersa. Su función optimize devuelve un conjunto de parámetros que corresponde a todos los parámetros numéricos del flujo de trabajo.

jlio = JaccardLabelImageOptimizer(w)
best_param = jlio.optimize("labeled", ground_truth, maxiter=20)
best_param
array([4.80023582e+00, 4.44562637e+00, 3.84861161e-04])

Luego podemos usar el optimizador para establecer estos parámetros en el flujo de trabajo y después leer dónde en el flujo de trabajo se establecieron los parámetros.

jlio.set_numeric_parameters(best_param)

# before printing the workflow, we quickly remove the input image
w.remove('input')
print(w)
Workflow:
blurred <- (<function gaussian_blur at 0x0000023723085A60>, 'input', None, 4.8002358210977345, 4.445626372447739, 0.00038486116050511713)
binarized <- (<function threshold_otsu at 0x00000237232EADC0>, 'blurred')
labeled <- (<function connected_components_labeling_box at 0x000002372316AB80>, 'binarized')

Después de establecer la entrada nuevamente, también podemos aplicar el flujo de trabajo a la imagen e inspeccionar el resultado visualmente.

w.set("input", imread("../../data/blobs.tif"))
cle.imshow(w.get("labeled"), labels=True)
../_images/9670bee784477649f403b50b1b7d253b75fa69d0f8cbcf5b779cd6bd7dba88f7.png

Más información sobre la optimización#

El JaccardLabelImageOptimizer también permite echar un vistazo al proceso de optimización aplicado anteriormente.

attempt, quality = jlio.get_plot()

plt.plot(attempt, quality)
[<matplotlib.lines.Line2D at 0x23735c22c70>]
../_images/9a651798ca88ed0ba7674d01f32cc6492c4842b881cac216f5d56edf5751055c.png