Saya telah bermain-main dengan algoritma rekonstruksi tomografi baru-baru ini. Saya sudah memiliki implementasi kerja yang bagus dari FBP, ART, skema iterasi seperti SIRT / SART dan bahkan menggunakan aljabar linear lurus (lambat!). Pertanyaan ini bukan tentang salah satu dari teknik itu ; jawaban dari bentuk "mengapa ada orang yang melakukannya seperti itu, inilah beberapa kode FBP" bukan yang saya cari.
Hal berikutnya yang ingin saya lakukan dengan program ini adalah " melengkapi perangkat " dan mengimplementasikan apa yang disebut " metode rekonstruksi Fourier ". Pemahaman saya tentang ini pada dasarnya adalah bahwa Anda menerapkan 1D FFT ke sinogram "eksposur", mengatur mereka sebagai "jari-jari roda" radial dalam ruang 2D Fourier (bahwa ini adalah hal yang berguna untuk dilakukan mengikuti langsung dari teorema slice pusat) , interpolasi dari titik-titik tersebut ke kisi-kisi biasa dalam ruang 2D itu, dan kemudian dimungkinkan untuk membalik Fourier-transform untuk memulihkan target pemindaian asli.
Kedengarannya sederhana, tetapi saya belum beruntung mendapatkan rekonstruksi yang terlihat seperti target asli.
Kode Python (numpy / SciPy / Matplotlib) di bawah ini adalah tentang ekspresi paling ringkas yang bisa saya dapatkan dari apa yang saya coba lakukan. Saat dijalankan, ini menampilkan yang berikut:
Gambar 1: target
Gambar 2: sinogram dari target
Gambar 3: baris sinogram FFT-ed
Gambar 4: baris atas adalah ruang FFT 2D yang diinterpolasi dari baris sinogram Fourier-domain; baris bawah adalah (untuk tujuan perbandingan) 2D FFT langsung dari target. Ini adalah titik di mana saya mulai curiga; plot yang diinterpolasi dari sinogram FFT terlihat mirip dengan plot yang dibuat oleh 2D-FFT langsung target ... namun berbeda.
Gambar 5: transformasi invers-Fourier dari Gambar 4. Saya berharap ini akan sedikit lebih dikenali sebagai target daripada yang sebenarnya.
Ada ide yang saya lakukan salah? Tidak yakin apakah pemahaman saya tentang rekonstruksi metode Fourier secara mendasar cacat, atau hanya ada beberapa bug dalam kode saya.
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()
Jawaban:
OK akhirnya saya sudah memecahkan ini.
Triknya pada dasarnya adalah meletakkan beberapa
fftshift
/ifftshift
s di tempat yang tepat sehingga representasi ruang Fourier 2D tidak berosilasi liar dan ditakdirkan mustahil untuk diinterpolasi secara akurat. Setidaknya itulah yang saya pikir memperbaikinya. Sebagian besar pemahaman terbatas yang saya miliki tentang teori Fourier didasarkan pada perumusan integral yang berkesinambungan, dan saya selalu menemukan domain diskrit dan FFT sedikit ... aneh.Sementara saya menemukan kode matlab agak samar, saya harus menghargai implementasi ini untuk setidaknya memberi saya kepercayaan algoritma rekonstruksi ini dapat dinyatakan cukup kompak dalam lingkungan semacam ini.
Pertama saya akan menunjukkan hasil, lalu kode:
Gambar 1: target baru yang lebih kompleks.
Gambar 2: sinogram (OK OK, itu adalah transformasi Radon) dari target.
Gambar 3: baris FFT-ed dari sinogram (diplot dengan DC di tengah).
Gambar 4: sinogram FFT-ed diubah menjadi ruang FFT 2D (DC di tengah). Warna adalah fungsi dari nilai absolut.
Gambar 4a: Memperbesar bagian tengah ruang FFT 2D hanya untuk menunjukkan sifat radial dari data sinogram dengan lebih baik.
Gambar 5: Baris atas: ruang FFT 2D diinterpolasi dari baris sinogram FFT-ed yang disusun secara radial. Baris bawah: penampilan yang diharapkan dari 2D FFT-ing target.
Gambar 5a: Memperbesar bagian tengah dari subplot pada Gambar 5 untuk menunjukkan tampilan ini dalam persetujuan yang cukup bagus secara kualitatif.
Gambar 6: Tes asam: FFT 2D terbalik dari ruang FFT yang diinterpolasi memulihkan target. Lena masih terlihat cukup baik meskipun kami baru saja melewatinya (mungkin karena ada "jari-jari" sinogram yang cukup untuk menutupi pesawat FFT 2D cukup padat; hal-hal menjadi menarik jika Anda mengurangi jumlah sudut paparan sehingga ini tidak lagi benar ).
Ini kodenya; menampilkan plot dalam waktu kurang dari 15 detik pada SciPy 64bit Debian / Wheezy pada i7.
Pembaruan 2013-02-17: Jika Anda cukup tertarik untuk mengarungi lot itu, beberapa output lagi dari program belajar mandiri yang merupakan bagiannya dapat ditemukan dalam bentuk poster ini . Isi kode dalam repositori ini mungkin juga menarik (walaupun perhatikan kode ini tidak seefisien yang di atas). Saya mungkin mencoba dan mengemasnya kembali sebagai "notebook" IPython di beberapa titik.
sumber
Saya tidak tahu persis di mana masalahnya, tetapi teorema irisan berarti bahwa dua kasus khusus ini harus benar:
Jadi ikuti kode Anda dan cobalah untuk menemukan titik di mana ini berhenti menjadi setara, bekerja maju dari sinogram dan mundur dari FFT 2D yang dihasilkan.
Ini tidak beres:
2D FFT yang Anda hasilkan diputar 90 derajat dari yang seharusnya?
Saya sarankan bekerja dengan magnitudo dan fase daripada nyata dan imajiner, sehingga Anda dapat melihat lebih mudah apa yang terjadi:
(Sudut putih -inf melakukan
log(abs(0))
, mereka tidak masalah)sumber
Saya percaya bahwa alasan teoretis yang sebenarnya mengapa solusi pertama tidak berhasil berasal dari kenyataan bahwa rotasi dilakukan sehubungan dengan pusat gambar, menginduksi offset
[S/2, S/2]
, yang berarti bahwa setiap baris Andasinogram
bukan dari0
keS
, melainkan dari-S/2
keS/2
. Dalam contoh Anda, offset sebenarnyaoffset = np.floor(S/2.)
. Perhatikan bahwa ini berfungsi untukS
genap atau ganjil, dan setara dengan apa yang Anda lakukan dalam kode AndaS/2
(walaupun lebih eksplisit menghindari masalah, kapanS
afloat
, misalnya).Dugaan saya adalah bahwa fase penundaan pergeseran ini memperkenalkan dalam transformasi Fourier (FT) adalah pada asal dari apa yang Anda bicarakan dalam pesan kedua Anda: fase-fase itu kacau, dan orang perlu mengkompensasi pergeseran itu agar dapat menerapkan inversi dari transformasi Radon. Kita perlu menggali lebih dalam teori itu untuk memastikan apa yang sebenarnya dibutuhkan agar invers bekerja seperti yang diharapkan.
Untuk mengkompensasi offset itu, Anda dapat menggunakan fftshift seperti yang Anda lakukan (yang menempatkan pusat setiap baris di awal, dan karena menggunakan DFT sebenarnya sesuai dengan menghitung Transformasi Fourier dari sinyal S-periodik, Anda berakhir dengan hal yang benar. ), atau secara eksplisit mengkompensasi efek ini dalam transformasi Fourier kompleks, ketika menghitung
sinogram
FT. Dalam praktik, alih-alih:Anda dapat menghapus
ifftshift
dan mengalikan setiap baris dengan vektor korektif:Ini berasal dari properti transformasi Fourier, ketika mempertimbangkan waktu-shift (periksa halaman wikipedia FT untuk "shift theorem", dan terapkan untuk shift yang sama dengan
- offset
- karena kami meletakkan gambar kembali di sekitar tengah).Demikian juga, Anda dapat menerapkan strategi yang sama untuk rekonstruksi, dan menggantikannya
fftshift
dengan koreksi fase, di kedua dimensi, tetapi di arah lain (kompensasi kembali):Nah, ini tidak meningkatkan solusi Anda, tetapi lebih memberi cahaya pada aspek teoritis dari pertanyaan Anda. Semoga itu bisa membantu!
Selain itu, saya tidak begitu suka menggunakan
fftshift
karena cenderung mengacaukan carafft
penghitungannya. Namun, dalam hal ini, Anda harus meletakkan pusat FT di tengah gambar sebelum interpolasi untuk mendapatkanfft2
(atau setidaknya berhati-hati saat mengaturr
- sehingga Anda bisa membuatnya benar-benarfftshift
gratis!), Danfftshift
sangat berguna sana. Namun saya lebih suka untuk tetap menggunakan fungsi itu untuk tujuan visualisasi, dan tidak dalam "inti" perhitungan. :-)Salam Hormat,
Jean-Louis
PS: sudah mencoba merekonstruksi gambar tanpa memotong lingkaran? yang memberikan efek kabur yang cukup keren di sudut-sudut, akan menyenangkan jika memiliki fitur seperti itu di program-program seperti Instagram, bukan?
sumber