Di recente ho giocato con algoritmi di ricostruzione tomografica. Ho già buone implementazioni funzionanti di FBP, ART, uno schema iterativo simile a SIRT / SART e persino usando un'algebra lineare diritta (lenta!). Questa domanda non riguarda nessuna di quelle tecniche ; le risposte del modulo "perché qualcuno dovrebbe farlo in questo modo, ecco un po 'di codice FBP invece" non sono quello che sto cercando.
La prossima cosa che volevo fare con questo programma era " completare il set " e implementare il cosiddetto " metodo di ricostruzione di Fourier ". La mia comprensione di questo è fondamentalmente che si applica un FFT 1D alle "esposizioni" del sinogramma, si organizzano quelli come "raggi di una ruota" radiali nello spazio di Fourier 2D (che questa è una cosa utile da fare segue direttamente dal teorema della fetta centrale) , interpolare da quei punti a una griglia regolare in quello spazio 2D, e quindi dovrebbe essere possibile invertire la trasformata di Fourier per recuperare l'obiettivo di scansione originale.
Sembra semplice, ma non ho avuto molta fortuna a ottenere ricostruzioni che assomigliano al bersaglio originale.
Il codice Python (numpy / SciPy / Matplotlib) di seguito è l'espressione più concisa che potrei trovare di ciò che sto cercando di fare. Quando eseguito, visualizza quanto segue:
Figura 1: l'obiettivo
Figura 2: un sinogramma del bersaglio
Figura 3: le righe del sinogramma FFT
Figura 4: la riga superiore è lo spazio FFT 2D interpolato dalle righe del sinogramma del dominio Fourier; la riga inferiore è (a fini di confronto) la FFT 2D diretta del target. Questo è il punto in cui sto iniziando a diventare sospettoso; le trame interpolate dai sinogrammi FFT sembrano simili alle trame create direttamente dal 2D-FFT del bersaglio ... eppure diverse.
Figura 5: la trasformata inversa di Fourier di Figura 4. Avrei sperato che questo sarebbe un po 'più riconoscibile come bersaglio di quanto non sia in realtà.
Qualche idea su cosa sto facendo di sbagliato? Non sono sicuro che la mia comprensione della ricostruzione del metodo di Fourier sia fondamentalmente imperfetta o che ci sia qualche bug nel mio codice.
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()