최근에 단층 복원 알고리즘을 가지고 놀았습니다. 나는 이미 FBP, ART, SIRT / SART와 같은 반복 체계를 구현하고 직선 대수를 사용하여 느리게 작동합니다 (느린!). 이 질문은 그러한 기술에 관한 것이 아닙니다 . "누구도 그렇게했을까요? 여기에 FBP 코드가 있습니다"라는 대답은 내가 찾는 것이 아닙니다.
이 프로그램으로 다음에하고 싶었던 것은 " 세트를 완성 "하고 소위 " 푸리에 재구성 방법 "을 구현하는 것이 었습니다 . 이것에 대한 나의 이해는 기본적으로 1D FFT를 사이 노 그램 "노출"에 적용하고 2D 푸리에 공간에서 방사형 "바퀴 스포크"로 정렬한다는 것입니다 (중앙 슬라이스 정리에서 직접 수행하는 것이 유용한 것입니다) , 해당 점에서 해당 2D 공간의 일반 그리드로 보간 한 다음 역 푸리에 변환을 수행하여 원래 스캔 대상을 복구 할 수 있어야합니다.
간단하게 들리지만 원래 목표와 비슷한 재구성을 얻는 데 많은 운이 없었습니다.
아래의 Python (numpy / SciPy / Matplotlib) 코드는 내가하려고하는 일에서 얻을 수있는 가장 간결한 표현에 관한 것입니다. 실행되면 다음이 표시됩니다.
그림 1 : 목표
그림 2 : 대상의 사이 노 그램
그림 3 : FFT-ed 사이 노 그램 행
그림 4 : 상단 행은 푸리에 도메인 사이 노 그램 행에서 보간 된 2D FFT 공간입니다. 맨 아래 행은 (비교 목적으로) 대상의 직접 2D FFT입니다. 이것이 내가 의심스러워지기 시작하는 시점입니다. 사이 노 그램 FFT에서 보간 된 플롯은 대상을 직접 2D-FFT하여 만든 플롯과 비슷하지만 다릅니다.
그림 5 : 그림 4의 역 푸리에 변환. 이것이 실제보다 목표로 좀 더 인식되기를 바랐습니다.
내가 잘못하고있는 아이디어가 있습니까? 푸리에 메소드 재구성에 대한 이해가 근본적으로 결함이 있는지 또는 코드에 버그가 있는지 확실하지 않습니다.
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()