您发布的代码是滤波反投影(FBP)的一个很好的例子,我相信对于想要学习 FBP 基础的人来说可能很有用。可以使用该功能iradon(...)
在 MATLAB 中(参见here https://www.mathworks.com/help/images/ref/iradon.html)使用各种滤波器执行 FBP。当然,就您而言,重点是学习中心切片定理的基础,因此寻找捷径并不是重点。通过回答你的问题我也学到了很多,刷新了我的知识!
现在您的代码已得到完美注释并描述了需要采取的步骤。有一些微妙的[编程]问题需要修复,以便代码能够正常工作。
首先,傅里叶域中的图像表示可能最终会由于以下原因而丢失数组:floor(diagDim/2)
取决于正弦图的大小。我会把它改成round(diagDim/2)
拥有完整的数据集fimg
。请注意,如果处理不当,这可能会导致某些正弦图尺寸出现错误。我鼓励你想象fimg
了解缺失的数组是什么以及它为何重要。
第二个问题是您的正弦图需要转置以与您的算法保持一致。因此添加sino = sino'
。再次,我鼓励您尝试不使用此代码的代码,看看会发生什么!请注意,必须沿视图进行零填充,以避免由于锯齿而产生伪像。我将在这个答案中演示一个例子。
第三,也是最重要的一点,imContrib
是一个数组的临时持有者fimg
。因此,它必须保持与fimg
, so
imContrib = imContrib * fft(rampFilter_1d);
应替换为
imContrib(floor(diagDim/2), :) = imContrib(floor(diagDim/2), :)' .* rampFilter_1d;
请注意,斜坡滤波器在频域中是线性的(感谢@Cris Luengo 纠正了此错误)。因此,您应该放弃fft
in fft(rampFilter_1d)
因为该滤波器应用于频域(记住fft(x)
将 x 的域(例如时间、空间等)分解为其频率内容)。
现在是一个完整的示例来展示它如何使用改进的谢普-洛根体模 https://www.mathworks.com/help/images/ref/phantom.html#d120e206667:
angs = 0:359; % angles of rotation 0, 1, 2... 359
init_img = phantom('Modified Shepp-Logan', 100); % Initial image 2D [100 x 100]
sino = radon(init_img, angs); % Create a sinogram using radon transform
% Here is your function ....
% This step is necessary so that frequency information is preserved: we pad
% the sinogram with zeros so that this is ensured.
sino = padarray(sino, floor(size(sino,1)/2), 'both');
% Rotate the sinogram 90-degree to be compatible with your codes definition of view and radial positions
% dim 1 -> view
% dim 2 -> Radial position
sino = sino';
% diagDim should be the length of an individual row of the sinogram - don't
% hardcode this!
diagDim = size(sino, 2);
% The 2DFT (2D Fourier transform) of our image will start as a matrix of
% all zeros.
fimg = zeros(diagDim);
% Design your 1-d ramp filter.
rampFilter_1d = abs(linspace(-1, 1, diagDim))';
rowIndex = 1;
for nn = angs
% fprintf('rowIndex = %g => nn = %g\n', rowIndex, nn);
% Each contribution to the image's 2DFT will also begin as all zero.
imContrib = zeros(diagDim);
% Get the current row of the sinogram - use rowIndex.
curRow = sino(rowIndex,:);
% Take the 1D Fourier transform the current row - be careful, as it's
% necessary to perform ifftshift and fftshift as Matlab tends to
% place zero-frequency components of a spectrum at the edges.
fourierCurRow = fftshift(fft(ifftshift(curRow)));
% Place the Fourier-transformed sino row and place it at the center of
% the next image contribution. Add the ramp filter in Fourier domain.
imContrib(round(diagDim/2), :) = fourierCurRow;
imContrib(round(diagDim/2), :) = imContrib(round(diagDim/2), :)' .* rampFilter_1d; % <-- NOT fft(rampFilter_1d)
% Rotate the current image contribution to be at the correct angle on
% the 2D Fourier-space image.
imContrib = imrotate(imContrib, nn, 'crop');
% Add the current image contribution to the running representation of
% the image in Fourier space!
fimg = fimg + imContrib;
rowIndex = rowIndex + 1;
end
% Finally, just take the inverse 2D Fourier transform of the image! Don't
% forget - you may need an fftshift or ifftshift here.
rcon = fftshift(ifft2(ifftshift(fimg)));
请注意,您的图像具有复杂的价值。所以,我用imshow(abs(rcon),[])
显示图像。一些有用的图像(发人深省)以及最终的重建图像rcon
:
如果您注释掉零填充步骤(即注释掉sino = padarray(sino, floor(size(sino,1)/2), 'both');
):
请注意带零填充和不带零填充的重建图像中不同的对象大小。当正弦图用零填充时,对象会收缩,因为径向内容被压缩。