Une méthode simple pour calculer les moyennes d’intensité circulaire en images
Dans la science expérimentale des matériaux, nous recevons souvent des images telles que celle ci-dessous, appelée motif de diffraction des rayons X.
Dans ce cas, la symétrie de l’échantillon mesuré fait que les images ont des anneaux d’intensité constante, dit Bagues Debye-Scherrer. Pour nous, il s’agit de données redondantes, nous devons réduire cette image à un simple tracé de la distance radiale (depuis le centre de tous les anneaux) en fonction de l’intensité à chaque distance radiale. La façon la plus simple de le faire est de simplement prendre une ligne qui commence au centre et va radialement vers l’extérieur, enregistrant l’intensité à chaque point radial. Une méthode plus robuste, cependant, consiste à utiliser l’intensité moyenne de l’anneau entier, pour s’assurer que la variabilité est moyennée.
Il s’avère que c’est très simple à faire! L’exemple montré ici sera fait en utilisant le paquet Python numpy
et visualisé en utilisant matplotlib
. De plus, pour importer le fichier TIFF dans cet exemple, j’utiliserai un package appelé tifffile
, qui peut être trouvé ici.
Tout d’abord, nous importons le package que nous utiliserons:
# Import packages
import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np
from tifffile import imread, imshow
Maintenant, nous pouvons charger notre image en utilisant tifffile.imread
. Nous le faisons comme suit:
# Load our image
img = imread('DiffractionImage.tif')
Si nous voulons maintenant montrer notre image pour inspecter à quoi elle ressemble, nous pouvons utiliser les lignes de code suivantes:
# Show our image
imshow(img)
plt.show()
D’après l’inspection, nous constatons que le centre de tous les cercles est à la valeur de pixel de (1242, 642) – la 1242e ligne et 642e colonne. Donc, la première chose que nous voulons faire est de redéfinir les coordonnées des pixels afin que la distance radiale soit de 0 à ce point. Cette transformation comprendra 2 étapes:
- Créez deux grilles – une correspondant aux coordonnées x et l’autre aux coordonnées y
- Utilisez les valeurs x et y pour calculer la distance radiale à chaque point et créez une nouvelle grille – chaque point de cette nouvelle grille aura la valeur correspondant à la distance radiale de (1242, 642)
# Image center
cen_x = 642
cen_y = 1242# Get image parameters
a = img.shape[0]
b = img.shape[1]# Find radial distances
[X, Y] = np.meshgrid(np.arange(b) - cen_x, np.arange(a) - cen_y)
R = np.sqrt(np.square(X) + np.square(Y))
Nous allons maintenant initialiser nos variables pour le calcul de la moyenne. Ici, nous devons définir la résolution de notre moyenne. La ligne de code suivante crée un tableau appelé rad
avec des valeurs radiales qui vont de 1 pixel à la valeur radiale maximale dans notre grille. Le troisième argument définit la densité ou la rareté de nos points radiaux (dans ce cas, tous les 1 pixel). Ce tableau servira de valeurs x dans notre tracé final:
rad = np.arange(1, np.max(R), 1)
Maintenant, nous initialisons le tableau pour nos valeurs y (intensité). Nous créons un tableau de zéros de la même longueur que rad
(que nous changerons au fur et à mesure) et une variable d’index appelée index
, que nous utiliserons pour savoir où nous modifions l’intensité:
intensity = np.zeros(len(rad))
index = 0
Maintenant, nous pouvons utiliser une boucle pour calculer la moyenne à chaque distance radiale. Ici, un autre paramètre important que nous définissons est la taille du bac. Cela définit le nombre de pixels que nous incluons en plus de la distance radiale exacte que nous recherchons. Dans cet exemple, nous allons un bac de 1 pixel inférieur et supérieur à notre rayon d’intérêt:
bin_size = 1
Notre boucle se déroulera par les étapes suivantes:
- Nous utilisons notre
bin_size
pour masquer notre image – les seules valeurs qui restent seront celles qui sont démasquées (dans la plage de rayon qui nous intéresse) - Calculer la moyenne des valeurs masquées – cela nous donne l’intensité moyenne à une distance radiale donnée
- Attribuer l’indice de notre
intensity
tableau à la valeur moyenne calculée à l’étape 2 - Répétez les étapes 1 à 3 jusqu’à ce que nous ayons répété la totalité
rad
tableau
for i in rad:
mask = (np.greater(R, i - bin_size) & np.less(R, i + bin_size)
values = img[mask]
intensity[index] = np.mean(values)
index += 1
Aussi simple que cela puisse paraître, nous avons maintenant terminé!
La dernière chose qui reste à faire est de visualiser notre nouvelle image à moyenne circulaire. Nous pouvons le faire comme suit (j’ai changé certains des paramètres de tracé, pour une explication plus détaillée, vous pouvez vous référer à mon article précédent):
# Adjust plot parameters
mpl.rcParams['font.family'] = 'Avenir'
mpl.rcParams['font.size'] = 16
mpl.rcParams['axes.linewidth'] = 2
mpl.rcParams['axes.spines.top'] = False
mpl.rcParams['axes.spines.right'] = False
mpl.rcParams['xtick.major.size'] = 7
mpl.rcParams['xtick.major.width'] = 2
mpl.rcParams['ytick.major.size'] = 7
mpl.rcParams['ytick.major.width'] = 2# Create figure and add subplot
fig = plt.figure()
ax = fig.add_subplot(111)# Plot data
ax.plot(rad, intensity, linewidth=2)# Edit axis labels
ax.set_xlabel('Radial Distance', labelpad=10)
ax.set_ylabel('Average Intensity', labelpad=10)
J’étais fasciné par l’élégance et la simplicité de faire une moyenne circulaire avec quelques lignes de code, donc je voulais créer un article étape par étape à montrer – j’espère que vous avez apprécié! Ce script fait partie d’un ensemble plus large d’outils que j’ai développé pour analyser les données de diffraction des rayons X, et peut être trouvé à ce Dépôt Github.
Merci pour la lecture! J’apprécie tout commentaire, et vous pouvez me trouver sur Twitter et connectez-vous avec moi sur LinkedIn pour plus de mises à jour et d’articles.