Détermination de la fonction d’étalement du point à partir d’une image de bille par moyenne#
Afin de déconvoluer correctement une image de microscopie, nous devrions déterminer la fonction d’étalement du point (PSF) du microscope.
Voir aussi
import numpy as np
from skimage.io import imread, imsave
from pyclesperanto_prototype import imshow
import pyclesperanto_prototype as cle
import pandas as pd
import matplotlib.pyplot as plt
Les données d’image d’exemple utilisées ici ont été acquises par Bert Nitzsche et Robert Haase (tous deux du MPI-CBG à l’époque) à l’installation de microscopie optique du MPI-CBG. Pour être complet, la taille des voxels est de 0,022x0,022x0,125 µm^3.
bead_image = imread('../../data/Bead_Image1_crop.tif')
bead_image.shape
(41, 150, 150)
Notre image d’exemple montre des billes fluorescentes, idéalement avec un diamètre inférieur à la résolution du dispositif d’imagerie. De plus, les billes devraient émettre de la lumière à la même longueur d’onde que l’échantillon que nous aimerions déconvoluer plus tard. Dans la coupe d’image suivante, nous voyons quatre billes fluorescentes. Il est recommandé d’imager un champ de vision plus large, avec au moins 25 billes. Assurez-vous également que les billes ne se collent pas entre elles et sont réparties de manière éparse.
imshow(cle.maximum_x_projection(bead_image), colorbar=True)
imshow(cle.maximum_y_projection(bead_image), colorbar=True)
imshow(cle.maximum_z_projection(bead_image), colorbar=True)
Pour déterminer une PSF moyenne, techniquement, nous pouvons découper toutes les billes individuelles, les aligner puis faire la moyenne des images. Par conséquent, nous segmentons les objets et déterminons leur centre de masse.
# Segmenter les objets
label_image = cle.voronoi_otsu_labeling(bead_image)
imshow(label_image, labels=True)
# déterminer le centre de masse pour chaque objet
stats = cle.statistics_of_labelled_pixels(bead_image, label_image)
df = pd.DataFrame(stats)
df[["mass_center_x", "mass_center_y", "mass_center_z"]]
| mass_center_x | mass_center_y | mass_center_z | |
|---|---|---|---|
| 0 | 30.107895 | 73.028938 | 23.327475 |
| 1 | 44.293156 | 111.633430 | 23.329062 |
| 2 | 76.092850 | 82.453033 | 23.299677 |
| 3 | 125.439606 | 35.972496 | 23.390951 |
Moyenne de la PSF#
Ensuite, nous allons itérer sur les billes et les découper en les transférant dans une image PSF plus petite.
# configurer la taille de la future image PSF
psf_radius = 20
size = psf_radius * 2 + 1
# initialiser la PSF
single_psf_image = cle.create([size, size, size])
avg_psf_image = cle.create([size, size, size])
num_psfs = len(df)
for index, row in df.iterrows():
x = row["mass_center_x"]
y = row["mass_center_y"]
z = row["mass_center_z"]
print("Bille", index, "à la position", x, y, z)
# déplacer la PSF dans la bonne position dans une image plus petite
cle.translate(bead_image, single_psf_image,
translate_x= -x + psf_radius,
translate_y= -y + psf_radius,
translate_z= -z + psf_radius)
# visualiser
fig, axs = plt.subplots(1,3)
imshow(cle.maximum_x_projection(single_psf_image), plot=axs[0])
imshow(cle.maximum_y_projection(single_psf_image), plot=axs[1])
imshow(cle.maximum_z_projection(single_psf_image), plot=axs[2])
# moyenne
avg_psf_image = avg_psf_image + single_psf_image / num_psfs
Bead 0 at position 30.107894897460938 73.02893829345703 23.32747459411621
Bead 1 at position 44.293155670166016 111.63343048095703 23.32906150817871
Bead 2 at position 76.09284973144531 82.45303344726562 23.2996768951416
Bead 3 at position 125.43960571289062 35.972496032714844 23.39095115661621
La PSF moyenne ressemble alors à ceci :
fig, axs = plt.subplots(1,3)
imshow(cle.maximum_x_projection(avg_psf_image), plot=axs[0])
imshow(cle.maximum_y_projection(avg_psf_image), plot=axs[1])
imshow(cle.maximum_z_projection(avg_psf_image), plot=axs[2])
avg_psf_image.min(), avg_psf_image.max()
(0.0, 94.5)
Après avoir déterminé une PSF bien centrée, nous pouvons la sauvegarder pour une utilisation ultérieure. Avant cela, nous normalisons la PSF. L’objectif est d’avoir une image où l’intensité totale est 1. Cela garantit qu’une image qui est déconvoluée en utilisant cette PSF plus tard ne modifie pas la gamme d’intensité de l’image.
normalized_psf = avg_psf_image / np.sum(avg_psf_image)
imshow(normalized_psf, colorbar=True)
normalized_psf.min(), normalized_psf.max()
(0.0, 0.0006259646)
imsave('../../data/psf.tif', normalized_psf)
C:\Users\rober\AppData\Local\Temp\ipykernel_16716\3265681491.py:1: UserWarning: ../../data/psf.tif is a low contrast image
imsave('../../data/psf.tif', normalized_psf)