He estado jugando con algoritmos de reconstrucción tomográfica recientemente. Ya tengo buenas implementaciones de trabajo de FBP, ART, un esquema iterativo tipo SIRT / SART e incluso uso de álgebra lineal recta (¡lento!). Esta pregunta no se trata de ninguna de esas técnicas ; las respuestas de la forma "por qué alguien lo haría de esa manera, aquí hay algo de código FBP" no son lo que estoy buscando.
Lo siguiente que quería hacer con este programa era " completar el conjunto " e implementar el llamado " método de reconstrucción de Fourier ". Comprendo que esto es básicamente que usted aplica una FFT 1D a las "exposiciones" del sinograma, las organiza como "radios radiales de una rueda" en el espacio de Fourier 2D (que esto es algo útil que se sigue directamente del teorema del corte central) , interpolar desde esos puntos a una cuadrícula regular en ese espacio 2D, y luego debería ser posible invertir la transformación de Fourier para recuperar el objetivo de escaneo original.
Suena simple, pero no he tenido mucha suerte de conseguir reconstrucciones que se parezcan al objetivo original.
El siguiente código de Python (numpy / SciPy / Matplotlib) es la expresión más concisa que pude encontrar de lo que estoy tratando de hacer. Cuando se ejecuta, muestra lo siguiente:
Figura 1: el objetivo
Figura 2: un sinograma del objetivo
Figura 3: las filas del sinograma FFT-ed
Figura 4: la fila superior es el espacio FFT 2D interpolado de las filas del sinograma del dominio de Fourier; la fila inferior es (para fines de comparación) la FFT 2D directa del objetivo. Este es el punto en el que empiezo a sospechar; las gráficas interpoladas a partir de las FFT de sinograma se parecen a las gráficas hechas directamente con 2D-FFT al objetivo ... y, sin embargo, diferentes.
Figura 5: la transformada inversa de Fourier de la Figura 4. Esperaba que esto fuera un poco más reconocible como objetivo de lo que realmente es.
¿Alguna idea de lo que estoy haciendo mal? No estoy seguro si mi comprensión de la reconstrucción del método de Fourier es fundamentalmente defectuosa, o si solo hay algún error en mi código.
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()