Mesures d’objets dans des images en mosaïque#
Pour certaines tâches spécifiques d’analyse d’images, il pourrait être possible de surmonter des limitations telles que l’application de l’étiquetage des composants connectés.
Par exemple, lors de la mesure de la taille des objets et si ces objets sont de taille limitée, il n’est pas nécessaire de combiner les résultats intermédiaires du traitement d’image en grandes images. Nous pourrions simplement mesurer les propriétés des objets pour tous les objets dans les tuiles, puis combiner le résultat de la quantification.
import numpy as np
import dask
import dask.array as da
from skimage.data import cells3d
from skimage.io import imread
import pyclesperanto_prototype as cle
from pyclesperanto_prototype import imshow
Notre point de départ est à nouveau une image binaire montrant des objets segmentés.
image = imread("../../data/blobs.tif") > 128
imshow(image)
Cette fois, nous voudrions mesurer la taille des objets et visualiser cela dans une image paramétrique. À des fins de démonstration, nous exécutons d’abord cette opération sur l’ensemble de l’image d’exemple.
def area_map(image):
"""
Label objects in a binary image and produce a pixel-count-map image.
"""
labels = cle.connected_components_labeling_box(image)
result = cle.pixel_count_map(labels)
return np.asarray(result)
reference = area_map(image)
cle.imshow(reference, colorbar=True)
Si nous traitons la même chose en tuiles, nous obtiendrons des résultats légèrement erronés en raison du problème d’étiquetage des composants connectés en tuiles démontré précédemment.
# tile the image
tiles = da.from_array(image, chunks=(128, 128))
# setup the operation we want to apply
procedure = area_map
# setup the tiling
tile_map = da.map_blocks(procedure, tiles)
# compute result
result = tile_map.compute()
# visualize
imshow(result, colorbar=True)
Encore une fois, les erreurs sont visibles à la bordure et nous pouvons les visualiser par comparaison directe :
absolute_error = cle.absolute_difference(result, reference)
cle.imshow(absolute_error, colorbar=True)
Pour éviter cette erreur, nous devons à nouveau réfléchir au traitement des tuiles d’image avec un chevauchement. Dans cet exemple particulier, nous n’exécutons aucune opération qui prend en compte les pixels voisins. Par conséquent, nous ne pouvons pas estimer le chevauchement nécessaire à partir de tels paramètres. Nous devons prendre en compte la taille maximale (diamètre) des objets. Nous pourrions aussi le faire de manière empirique, comme précédemment. Par conséquent, calculons d’abord l’erreur quadratique moyenne des deux résultats d’exemple ci-dessus :
cle.mean_squared_error(result, reference)
4338.783956692913
Ensuite, nous pouvons calculer cette erreur dans une boucle en faisant varier la taille du chevauchement à l’aide de dask.array.map_overlay tout en traitant l’image en tuiles. Notez que nous définissons boundary=0 ici, car sinon les objets s’étendraient dans l’image binaire et les mesures de taille seraient erronées.
for overlap_width in range(0, 30, 5):
print("Largeur de chevauchement", overlap_width)
tile_map = da.map_overlap(procedure, tiles, depth=overlap_width, boundary=0)
result = tile_map.compute()
print("erreur quadratique moyenne", cle.mean_squared_error(result, reference))
print("-----------------------------------")
Overlap width 0
mean squared error 4338.783956692913
-----------------------------------
Overlap width 5
mean squared error 1702.8293553149606
-----------------------------------
Overlap width 10
mean squared error 460.85811392716533
-----------------------------------
Overlap width 15
mean squared error 70.78670952263779
-----------------------------------
Overlap width 20
mean squared error 1.2793891486220472
-----------------------------------
Overlap width 25
mean squared error 0.0
-----------------------------------
Le chevauchement déterminé empiriquement où cette erreur devient 0 est une estimation optimiste. Lorsque vous utilisez cette méthode dans votre exemple, assurez-vous d’appliquer un chevauchement plus grand que la valeur déterminée.
Remarque : Les fonctions compute et imshow peuvent ne pas fonctionner sur de grands ensembles de données car les images peuvent ne pas tenir dans la mémoire de l’ordinateur. Nous les utilisons ici à des fins de démonstration.
overlap_width = 30
tile_map = da.map_overlap(procedure, tiles, depth=overlap_width, boundary=0)
result = tile_map.compute()
cle.imshow(tile_map, colorbar=True)