Classification d’objets sur des GPU compatibles OpenCL#

APOC est basé sur pyclesperanto et scikit-learn. Il permet de classer des objets selon des propriétés / caractéristiques mesurées telles que l’intensité, la forme et le nombre de cellules voisines.

import apoc

from skimage.io import imread, imsave
import pyclesperanto_prototype as cle
import numpy as np
import matplotlib.pyplot as plt

Pour la classification d’objets, nous avons besoin d’une image d’intensité et d’une image d’étiquettes en entrée.

# load intensity image
image = imread('../../data/blobs.tif')

# segment the image
labels = cle.label(cle.threshold_otsu(image))

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

cle.imshow(image, color_map="Greys_r", plot=axs[0])
cle.imshow(labels, labels=True, plot=axs[1])
../_images/fa297a6ff94d7e67daf1bf1ec0ab5638bddf284678939e68cfd3b433292d0378.png

Entraînement#

Nous avons également besoin d’une image d’annotation de vérité terrain. Cette image est aussi une image d’étiquettes avec une annotation éparse. Une ligne avec la valeur 1 a été tracée à travers tous les objets qui sont censés appartenir à la classe 1. Une ligne avec la valeur 2 a été tracée à travers tous les objets qui devraient être classés comme classe 2. Si la ligne traverse l’arrière-plan, cela est ignoré. Dans cet exemple, les objets ont été annotés en trois classes :

  • Objets allongés

  • Objets arrondis

  • Petits objets

annotation = cle.push(imread('../../data/label_annotation.tif'))

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

cle.imshow(labels, labels=True, plot=axs[0])
cle.imshow(annotation, labels=True, plot=axs[1])
../_images/146b524bd41585fb8be17f58fbde072c865befc7981ca2a0a1efd152448fd340.png

Ensuite, nous devons définir quelles caractéristiques nous voulons utiliser pour classer les objets. Nous utiliserons la surface, la forme et l’écart-type de l’intensité.

features = 'area mean_max_distance_to_centroid_ratio standard_deviation_intensity'
# Create an object classifier
filename = "../../data/blobs_object_classifier.cl"
classifier = apoc.ObjectClassifier(filename)

# train it; after training, it will be saved to the file specified above
classifier.train(features, labels, annotation, image)

Une fois que le classificateur a été entraîné, nous pouvons l’utiliser immédiatement pour prédire la classification des objets dans l’image.

# determine object classification
classification_result = classifier.predict(labels, image)

cle.imshow(classification_result, labels=True)
../_images/f39c851ff0b77b66b8cc4045185abf5ddb35f8fb60dcadc3704c6b6ae598d23a.png

Prédiction#

Vous pouvez également recharger le classificateur depuis le disque et l’appliquer à d’autres images. Nous allons simuler cela en faisant pivoter l’image originale. C’est d’ailleurs un bon test de santé pour voir si la classification dépend de l’orientation de l’image.

image2 = cle.rotate(image, angle_around_z_in_degrees=90)
labels2 = cle.rotate(labels, angle_around_z_in_degrees=90)
classifier2 = apoc.ObjectClassifier("../../data/blobs_object_classifier.cl")

classification_result2 = classifier2.predict(labels2, image2)

cle.imshow(classification_result2, labels=True)
../_images/01f6b12bedc4242bef52b89fea7595aefd441139067670817bdbc8b49344b559.png

Caractéristiques disponibles pour la classification d’objets#

Nous pouvons afficher toutes les caractéristiques disponibles. Les paramètres avec un ? attendent un nombre à cette position et peuvent être spécifiés plusieurs fois avec plusieurs valeurs.

apoc.list_available_object_classification_features()
['label',
 'original_label',
 'bbox_min_x',
 'bbox_min_y',
 'bbox_min_z',
 'bbox_max_x',
 'bbox_max_y',
 'bbox_max_z',
 'bbox_width',
 'bbox_height',
 'bbox_depth',
 'min_intensity',
 'max_intensity',
 'sum_intensity',
 'area',
 'mean_intensity',
 'sum_intensity_times_x',
 'mass_center_x',
 'sum_intensity_times_y',
 'mass_center_y',
 'sum_intensity_times_z',
 'mass_center_z',
 'sum_x',
 'centroid_x',
 'sum_y',
 'centroid_y',
 'sum_z',
 'centroid_z',
 'sum_distance_to_centroid',
 'mean_distance_to_centroid',
 'sum_distance_to_mass_center',
 'mean_distance_to_mass_center',
 'standard_deviation_intensity',
 'max_distance_to_centroid',
 'max_distance_to_mass_center',
 'mean_max_distance_to_centroid_ratio',
 'mean_max_distance_to_mass_center_ratio',
 'touching_neighbor_count',
 'average_distance_of_touching_neighbors',
 'average_distance_of_n_nearest_neighbors=?',
 'average_distance_of_n_nearest_neighbors=?']