J'ai récemment joué avec des algorithmes de reconstruction tomographique. J'ai déjà de belles implémentations de travail de FBP, ART, un schéma itératif de type SIRT / SART et même en utilisant l'algèbre linéaire droite (lente!). Cette question ne concerne aucune de ces techniques ; les réponses du formulaire "pourquoi quelqu'un le ferait-il de cette façon, voici du code FBP à la place" ne sont pas ce que je recherche.
La prochaine chose que je voulais faire avec ce programme était de « compléter l'ensemble » et de mettre en œuvre la soi-disant « méthode de reconstruction de Fourier ». Ma compréhension de cela est essentiellement que vous appliquez une FFT 1D aux "expositions" sinogrammes, que vous les organisez comme des "rayons d'une roue" radiaux dans l'espace de Fourier 2D (que c'est une chose utile à faire découle directement du théorème de la tranche centrale) , interpoler à partir de ces points vers une grille régulière dans cet espace 2D, puis il devrait être possible d'inverser la transformée de Fourier pour récupérer la cible de balayage d'origine.
Cela semble simple, mais je n'ai pas eu beaucoup de chance d'obtenir des reconstructions qui ressemblent à la cible d'origine.
Le code Python (numpy / SciPy / Matplotlib) ci-dessous est à propos de l'expression la plus concise que j'ai pu trouver de ce que j'essaie de faire. Lorsqu'il est exécuté, il affiche les éléments suivants:
Figure 1: la cible
Figure 2: un sinogramme de la cible
Figure 3: les rangées de sinogrammes FFT-ed
Figure 4: la rangée du haut est l'espace FFT 2D interpolé à partir des rangées de sinogrammes du domaine de Fourier; la ligne du bas est (à des fins de comparaison) la FFT 2D directe de la cible. C'est le moment où je commence à devenir suspect; les tracés interpolés à partir des FFT sinogrammes ressemblent aux tracés réalisés en FFT 2D directement sur la cible ... et pourtant différents.
Figure 5: la transformée de Fourier inverse de la figure 4. J'aurais espéré que ce serait un peu plus reconnaissable comme cible qu'elle ne l'est réellement.
Des idées sur ce que je fais mal? Je ne sais pas si ma compréhension de la reconstruction de la méthode de Fourier est fondamentalement erronée, ou il y a juste un bug dans mon code.
import math
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
import scipy.interpolate
import scipy.fftpack
import scipy.ndimage.interpolation
S=256 # Size of target, and resolution of Fourier space
A=359 # Number of sinogram exposures
# Construct a simple test target
target=np.zeros((S,S))
target[S/3:2*S/3,S/3:2*S/3]=0.5
target[120:136,100:116]=1.0
plt.figure()
plt.title("Target")
plt.imshow(target)
# Project the sinogram
sinogram=np.array([
np.sum(
scipy.ndimage.interpolation.rotate(
target,a,order=1,reshape=False,mode='constant',cval=0.0
)
,axis=1
) for a in xrange(A)
])
plt.figure()
plt.title("Sinogram")
plt.imshow(sinogram)
# Fourier transform the rows of the sinogram
sinogram_fft_rows=scipy.fftpack.fftshift(
scipy.fftpack.fft(sinogram),
axes=1
)
plt.figure()
plt.subplot(121)
plt.title("Sinogram rows FFT (real)")
plt.imshow(np.real(np.real(sinogram_fft_rows)),vmin=-50,vmax=50)
plt.subplot(122)
plt.title("Sinogram rows FFT (imag)")
plt.imshow(np.real(np.imag(sinogram_fft_rows)),vmin=-50,vmax=50)
# Coordinates of sinogram FFT-ed rows' samples in 2D FFT space
a=(2.0*math.pi/A)*np.arange(A)
r=np.arange(S)-S/2
r,a=np.meshgrid(r,a)
r=r.flatten()
a=a.flatten()
srcx=(S/2)+r*np.cos(a)
srcy=(S/2)+r*np.sin(a)
# Coordinates of regular grid in 2D FFT space
dstx,dsty=np.meshgrid(np.arange(S),np.arange(S))
dstx=dstx.flatten()
dsty=dsty.flatten()
# Let the central slice theorem work its magic!
# Interpolate the 2D Fourier space grid from the transformed sinogram rows
fft2_real=scipy.interpolate.griddata(
(srcy,srcx),
np.real(sinogram_fft_rows).flatten(),
(dsty,dstx),
method='cubic',
fill_value=0.0
).reshape((S,S))
fft2_imag=scipy.interpolate.griddata(
(srcy,srcx),
np.imag(sinogram_fft_rows).flatten(),
(dsty,dstx),
method='cubic',
fill_value=0.0
).reshape((S,S))
plt.figure()
plt.suptitle("FFT2 space")
plt.subplot(221)
plt.title("Recon (real)")
plt.imshow(fft2_real,vmin=-10,vmax=10)
plt.subplot(222)
plt.title("Recon (imag)")
plt.imshow(fft2_imag,vmin=-10,vmax=10)
# Show 2D FFT of target, just for comparison
expected_fft2=scipy.fftpack.fftshift(scipy.fftpack.fft2(target))
plt.subplot(223)
plt.title("Expected (real)")
plt.imshow(np.real(expected_fft2),vmin=-10,vmax=10)
plt.subplot(224)
plt.title("Expected (imag)")
plt.imshow(np.imag(expected_fft2),vmin=-10,vmax=10)
# Transform from 2D Fourier space back to a reconstruction of the target
fft2=scipy.fftpack.ifftshift(fft2_real+1.0j*fft2_imag)
recon=np.real(scipy.fftpack.ifft2(fft2))
plt.figure()
plt.title("Reconstruction")
plt.imshow(recon,vmin=0.0,vmax=1.0)
plt.show()