Mosaïque d’images avec chevauchement#

Lors du traitement d’images en tuiles, nous pouvons observer des artefacts sur les bordures des tuiles dans l’image résultante. Une stratégie pour prévenir ces artefacts consiste à traiter les tuiles avec un certain chevauchement. dask prend également en charge cette approche. Encore une fois, à des fins de démonstration, nous utilisons imshow pour afficher les images résultantes. Si nous traitions de grandes données, la fonction imshow ne fonctionnerait pas.

import dask
import dask.array as da
from skimage.filters import gaussian
from skimage.data import cells3d
from pyclesperanto_prototype import imshow

De manière similaire à l’exemple de la leçon précédente, nous définissons une procédure qui applique un flou gaussien à une image et affiche la taille de l’image, juste pour que nous sachions :

def procedure(image):
    print("proceduring", image.shape)
    return gaussian(image, sigma=5)
image = cells3d()[30,1]
imshow(image)
../_images/e6d2393f7c605c769fb82b772552ade1566917e2a294f57aa9e4f747b0c78793.png

Après avoir chargé l’image, nous la découpons en tuiles comme d’habitude.

tiles = da.from_array(image, chunks=(128, 128))
tiles
Array Chunk
Bytes 128.00 kiB 32.00 kiB
Shape (256, 256) (128, 128)
Count 4 Tasks 4 Chunks
Type uint16 numpy.ndarray
256 256

Ensuite, nous indiquons à dask ce qu’il faut faire avec nos tuiles : nous voulons appliquer la fonction procedure aux tuiles avec un chevauchement défini.

overlap_width = 1
tile_map = da.map_overlap(procedure, tiles, depth=overlap_width)
proceduring (0, 0)
proceduring (1, 1)
/Users/haase/opt/anaconda3/envs/bio_39/lib/python3.9/site-packages/dask/array/overlap.py:642: FutureWarning: Default 'boundary' argument value will change from 'reflect' to 'none' in future versions from 2022.03.0 onwards. Use 'boundary="none"' to opt into the future behavior now or set 'boundary="reflect"' to maintain the current behavior going forward.
  warnings.warn(

La fonction a été exécutée deux fois avec de très petites images (0x0 et 1x1 pixels) pour vérifier si elle fonctionne. Ensuite, nous calculons effectivement le résultat.

result = tile_map.compute() # Avertissement : Ceci charge toutes les données d'image en mémoire
proceduringproceduring (130, 130)
proceduring (130, 130)
 (130, 130)
proceduring (130, 130)

D’après la taille d’image imprimée, nous pouvons voir que la taille de l’image traitée est 2 pixels plus grande que la taille de la tuile. C’est le chevauchement de 1 pixel dans toutes les directions.

Minimisation des effets de bord#

Ensuite, nous allons comparer le résultat du traitement de l’image entière avec l’image traitée en tuiles avec différents chevauchements. Cela nous donne l’occasion de déterminer la largeur de chevauchement minimale nécessaire pour éliminer les effets de bord. Tout d’abord, nous calculons le résultat pour l’image complète.

untiled_result = procedure(image)
proceduring (256, 256)

Ensuite, nous exécutons une boucle for avec différentes border_widths.

for overlap_width in range(0, 25, 5):
    print("Overlap width", overlap_width)
    tile_map = da.map_overlap(procedure, tiles, depth=overlap_width, boundary='nearest')
    result = tile_map.compute()
    difference = result - untiled_result
    imshow(difference)
    print("sum difference", difference.sum())
    print("-----------------------------------")
Overlap width 0
proceduring (0, 0)
proceduring (1, 1)
proceduringproceduring (128, 128)
proceduring (128, 128) (128, 128)

proceduring (128, 128)
../_images/e4126918c50e4b551767159a05ace9b17cb60db4891f34ce4000369b3cfe9c54.png
sum difference 1.528818863147824
-----------------------------------
Overlap width 5
proceduring (0, 0)
proceduring (1, 1)
proceduring (138, 138)
proceduring (138, 138)
proceduring (138, 138)
proceduring (138, 138)
../_images/13eb6b058a8c32ec6d6cdd255cc7627467c4e18c5cc7345049e9843d1ec85552.png
sum difference 2.098167990865754
-----------------------------------
Overlap width 10
proceduring (0, 0)
proceduring (1, 1)
proceduringproceduring (148, 148)
 (148, 148)
proceduring (148, 148)
proceduring (148, 148)
../_images/4ba9572136695137b5fa129099e0fd00fbf9be14726ad27fc105eb7ac77396b6.png
sum difference -0.18132395183423158
-----------------------------------
Overlap width 15
proceduring (0, 0)
proceduring (1, 1)
proceduring (158, 158)
proceduring (158, 158)
proceduring (158, 158)
proceduring (158, 158)
../_images/475a541b79caf5ff201e8f11ef3f1c1d04afbb786c252c87e5ee31d2d560ac53.png
sum difference -0.005761703866654207
-----------------------------------
Overlap width 20
proceduring (0, 0)
proceduring (1, 1)
proceduring (168, 168)
proceduring (168, 168)
proceduring (168, 168)
proceduring (168, 168)
../_images/48eebdd7f37bda714d1326c6ccf8d5b9a96db531693e290ee45bd898b2277a4e.png
sum difference 0.0
-----------------------------------

Comme vous pouvez le voir, pour éliminer complètement l’effet de bord, nous devons utiliser un chevauchement de 25 pixels. Ceci est évidemment lié à la procedure que nous avons appliquée. Dans notre cas, le flou gaussien utilisé dans procedure a été configuré avec sigma=5. En règle générale, nous pouvons dire que dans le cas d’un flou gaussien, la largeur de la bordure doit être au moins quatre fois le sigma configuré. Cependant, lors de l’utilisation d’algorithmes plus compliqués, il n’existe pas de telles règles. En général, il est recommandé de tester le traitement d’images en tuiles sur de petites images comme démontré ici et de déterminer si des artefacts apparaissent et quelles erreurs ils peuvent causer dans un flux de traitement d’images plus long.