Selección de características#
Al seleccionar las características adecuadas, hay algunas reglas generales que se pueden tener en cuenta. Por ejemplo, si se quiere segmentar objetos con mucha precisión, se deben usar valores pequeños de radio / sigma. Si es suficiente un contorno aproximado, o si se deben eliminar píxeles individuales en los bordes de los objetos, tiene sentido usar valores más grandes de radio y sigma. Sin embargo, este tema también se puede abordar utilizando estadísticas.
from skimage.io import imread, imsave
import pyclesperanto_prototype as cle
import numpy as np
import apoc
import matplotlib.pyplot as plt
import pandas as pd
image = imread('../../data/blobs.tif')
manual_annotation = imread('../../data/blobs_annotations.tif')
fig, axs = plt.subplots(1,2)
cle.imshow(image, plot=axs[0])
cle.imshow(manual_annotation, labels=True, plot=axs[1])
Entrenamiento - con demasiadas características#
Ahora entrenamos un segmentador de objetos y proporcionamos muchas características. También necesitamos proporcionar parámetros para configurar árboles de decisión profundos y muchos árboles. Esto es necesario para que los siguientes pasos, derivando estadísticas, tengan suficiente poder estadístico. Después, echamos un vistazo al resultado para una rápida comprobación de coherencia.
# define features
features = apoc.PredefinedFeatureSet.small_dog_log.value + " " + \
apoc.PredefinedFeatureSet.medium_dog_log.value + " " + \
apoc.PredefinedFeatureSet.large_dog_log.value
# this is where the model will be saved
cl_filename = '../../data/blobs_object_segmenter2.cl'
apoc.erase_classifier(cl_filename)
classifier = apoc.ObjectSegmenter(opencl_filename=cl_filename,
positive_class_identifier=2,
max_depth=5,
num_ensembles=1000)
classifier.train(features, manual_annotation, image)
segmentation_result = classifier.predict(features=features, image=image)
cle.imshow(segmentation_result, labels=True)
Estadísticas del clasificador#
Después del entrenamiento, podemos imprimir algunas estadísticas del clasificador. Nos proporciona una tabla de las características utilizadas y cuán importantes fueron las características para tomar la decisión de clasificación de píxeles.
shares, counts = classifier.statistics()
def colorize(styler):
styler.background_gradient(axis=None, cmap="rainbow")
return styler
df = pd.DataFrame(shares).T
df.style.pipe(colorize)
| 0 | 1 | 2 | 3 | 4 | |
|---|---|---|---|---|---|
| original | 0.138000 | 0.046423 | 0.042312 | 0.037281 | 0.062112 |
| gaussian_blur=1 | 0.228000 | 0.092846 | 0.074303 | 0.105263 | 0.055901 |
| difference_of_gaussian=1 | 0.000000 | 0.108828 | 0.095975 | 0.074561 | 0.086957 |
| laplace_box_of_gaussian_blur=1 | 0.000000 | 0.105784 | 0.089783 | 0.081140 | 0.099379 |
| gaussian_blur=5 | 0.096000 | 0.064688 | 0.118679 | 0.096491 | 0.130435 |
| difference_of_gaussian=5 | 0.254000 | 0.182648 | 0.112487 | 0.120614 | 0.118012 |
| laplace_box_of_gaussian_blur=5 | 0.209000 | 0.194064 | 0.121775 | 0.118421 | 0.124224 |
| gaussian_blur=25 | 0.004000 | 0.061644 | 0.113519 | 0.127193 | 0.080745 |
| difference_of_gaussian=25 | 0.032000 | 0.072298 | 0.122807 | 0.127193 | 0.130435 |
| laplace_box_of_gaussian_blur=25 | 0.039000 | 0.070776 | 0.108359 | 0.111842 | 0.111801 |
En esta visualización se puede ver que las características gaussian_blur=1, difference_of_gaussian=5 y laplace_box_of_gaussian_blur=5 representan alrededor del 65% de la decisión. En el primer nivel (nivel 0). Si estas tres características son cruciales, podemos entrenar otro clasificador que solo tenga en cuenta estas características. Además, vemos que la proporción de las características utilizadas en los tres niveles de profundidad superiores está distribuida de manera más uniforme. Estos niveles pueden no marcar una gran diferencia al clasificar píxeles. El próximo clasificador que entrenemos, lo podemos entrenar con un max_depth más bajo.
# define features
features = "gaussian_blur=1 difference_of_gaussian=5 laplace_box_of_gaussian_blur=5"
# this is where the model will be saved
cl_filename = '../../data/blobs_object_segmenter3.cl'
apoc.erase_classifier(cl_filename)
classifier = apoc.ObjectSegmenter(opencl_filename=cl_filename,
positive_class_identifier=2,
max_depth=3,
num_ensembles=1000)
classifier.train(features, manual_annotation, image)
segmentation_result = classifier.predict(features=features, image=image)
cle.imshow(segmentation_result, labels=True)
El nuevo clasificador aún produce un resultado muy similar. Tiene en cuenta menos características, lo que lo hace más rápido, pero potencialmente también menos robusto frente a diferencias entre imágenes y condiciones de imagen. Simplemente echamos otro vistazo a las estadísticas del clasificador:
shares, counts = classifier.statistics()
df = pd.DataFrame(shares).T
df.style.pipe(colorize)
| 0 | 1 | 2 | |
|---|---|---|---|
| gaussian_blur=1 | 0.331000 | 0.349194 | 0.344620 |
| difference_of_gaussian=5 | 0.356000 | 0.329839 | 0.337096 |
| laplace_box_of_gaussian_blur=5 | 0.313000 | 0.320968 | 0.318284 |
Con fines de demostración, ahora entrenaremos otro clasificador con características muy similares.
# define features
features = "gaussian_blur=1 difference_of_gaussian=2 difference_of_gaussian=3 difference_of_gaussian=4 difference_of_gaussian=5 difference_of_gaussian=6 laplace_box_of_gaussian_blur=5"
# this is where the model will be saved
cl_filename = '../../data/blobs_object_segmenter3.cl'
apoc.erase_classifier(cl_filename)
classifier = apoc.ObjectSegmenter(opencl_filename=cl_filename,
positive_class_identifier=2,
max_depth=3,
num_ensembles=1000)
classifier.train(features, manual_annotation, image)
segmentation_result = classifier.predict(features=features, image=image)
cle.imshow(segmentation_result, labels=True)
Una vez más, el resultado de la segmentación se ve muy similar, pero la estadística del clasificador es diferente.
shares, counts = classifier.statistics()
df = pd.DataFrame(shares).T
df.style.pipe(colorize)
| 0 | 1 | 2 | |
|---|---|---|---|
| gaussian_blur=1 | 0.200000 | 0.093750 | 0.162829 |
| difference_of_gaussian=2 | 0.000000 | 0.120888 | 0.148026 |
| difference_of_gaussian=3 | 0.053000 | 0.064967 | 0.125000 |
| difference_of_gaussian=4 | 0.236000 | 0.162829 | 0.097039 |
| difference_of_gaussian=5 | 0.178000 | 0.222862 | 0.125822 |
| difference_of_gaussian=6 | 0.134000 | 0.120066 | 0.194901 |
| laplace_box_of_gaussian_blur=5 | 0.199000 | 0.214638 | 0.146382 |
De esta manera, también se pueden ajustar los parámetros de radio y sigma que se necesitan utilizar para las características especificadas.
Las sugerencias dadas aquí en esta sección no son reglas sólidas para seleccionar las características correctas. Sin embargo, las herramientas proporcionadas pueden ayudar a mirar un poco detrás de las características y a medir la influencia que tienen las listas de características y los parámetros proporcionados.