Simulation de la formation d’image + restauration d’image#

Dans ce notebook, nous assemblons artificiellement une image de microscope à partir de noyaux simulés, de bruit et d’arrière-plan. Ensuite, nous utilisons des techniques classiques de traitement d’image pour éliminer le bruit et l’arrière-plan.

import pyclesperanto_prototype as cle
import numpy as np
image_size = (100, 100)

# noise configuration
noise_level = 2

# background configuration
camera_offset = 100
background_sigma = 25
background_intensity = 5

# nuclei configuration
nuclei_radius = 5
nuclei_blur_sigma = 1
nuclei_number = 10
nuclei_intensity = 5
# by pinning the random seed, we can make the code repeatable
np.random.seed(42)

Bruit#

Ici, nous supposons que le bruit dans l’image suit une distribution de Poisson, une hypothèse courante en microscopie.

noise_image = np.random.poisson(noise_level, image_size)

cle.imshow(noise_image, colorbar=True)
../_images/a0be8d81e2a7b002e7841e89c7ac2ef43be4a5c58d9062e56886b3be8b5c308b.png

Arrière-plan#

L’intensité de l’arrière-plan dans les images de microscopie à fluorescence provient généralement de la lumière hors focus. Nous pouvons simuler cela en plaçant des sources lumineuses sous forme de pixels uniques et en les floutant avec un filtre gaussien. De plus, de nombreuses caméras de microscope ont ce qu’on appelle un décalage de caméra. Aucun pixel n’aura jamais une intensité inférieure à cette valeur.

# create empty image
background = np.zeros(image_size)

# place light sources
background[20, 10] += 1
background[50, 80] += 1
background[60, 50] += 1

# blur them massively
background = cle.gaussian_blur(background, sigma_x=background_sigma, sigma_y=background_sigma)

# normalize the image so that the maximum intensity has a defined value
background = background / background.max() * background_intensity

# add camera offsert
background = background + camera_offset

background
cle._ image
shape(100, 100)
dtypefloat32
size39.1 kB
min100.14104
max105.0

Noyaux#

Ensuite, nous plaçons des noyaux dans une image à des positions aléatoires. Nous les floutons un peu pour simuler la fonction d’étalement du point du microscope.

# retrieve a defined number of random positions
nuclei_positions = np.random.random((nuclei_number, 2)) * image_size

# write 1 at these locations
nuclei_image = cle.pointlist_to_labelled_spots(nuclei_positions.T, np.zeros(image_size))
nuclei_image = (nuclei_image > 0) * nuclei_intensity

# enlarge the nuclei by a define radius
nuclei_image = cle.maximum_sphere(nuclei_image, radius_x=nuclei_radius, radius_y=nuclei_radius)

# blur the image to make it look more realistic
nuclei_image = cle.gaussian_blur(nuclei_image, sigma_x=nuclei_blur_sigma, sigma_y=nuclei_blur_sigma)

nuclei_image
cle._ image
shape(100, 100)
dtypefloat32
size39.1 kB
min0.0
max5.0

Formation de l’image#

Une image de microscopie est la somme de la scène et des effets décrits ci-dessus.

sum_image = np.asarray(noise_image + background + nuclei_image)

cle.imshow(sum_image, colorbar=True)
../_images/731583ea9532d7236719d77e5d2767170a6c819272fc513fb07ef289008685dd.png

Segmentation d’image#

Si nous appliquions maintenant un algorithme de segmentation à cette image telle quelle, cela pourrait conduire à un résultat erroné.

binary = cle.threshold_otsu(sum_image.astype(np.float32))

binary
cle._ image
shape(100, 100)
dtypeuint8
size9.8 kB
min0.0
max1.0

Suppression de l’arrière-plan#

Pour résoudre ce problème, nous devons d’abord supprimer l’intensité de l’arrière-plan.

background_removed = cle.top_hat_box(sum_image, radius_x=10, radius_y=10)

background_removed
cle._ image
shape(100, 100)
dtypefloat32
size39.1 kB
min0.0
max12.833778

Suppression du bruit#

Nous pouvons également supprimer le bruit de l’image.

noise_removed1 = cle.mean_sphere(sum_image, radius_x=3, radius_y=3)

noise_removed1
cle._ image
shape(100, 100)
dtypefloat32
size39.1 kB
min101.35629
max111.36778

Et cela peut également être fait sur l’image dont l’arrière-plan a été soustrait.

noise_removed = cle.mean_sphere(background_removed, radius_x=3, radius_y=3)

noise_removed
cle._ image
shape(100, 100)
dtypefloat32
size39.1 kB
min0.7578272
max7.5516324

Segmentation d’image II#

Après avoir corrigé l’image, nous pouvons essayer la segmentation à nouveau.

binary2 = cle.threshold_otsu(noise_removed.astype(np.float32))

binary2
cle._ image
shape(100, 100)
dtypeuint8
size9.8 kB
min0.0
max1.0
# sneak preview: watershed
import napari_segment_blobs_and_things_with_membranes as nsbatwm
binary3 = nsbatwm.split_touching_objects(binary2)

binary3
<__array_function__ internals>:180: RuntimeWarning: Converting input from bool to <class 'numpy.uint8'> for compatibility.
nsbatwm made image
shape(100, 100)
dtypebool
size9.8 kB
minFalse
maxTrue