我正在使用中央切片定理进行作业分配的逆向投影算法,尽管我了解书面理论,但在Matlab中实现该问题时遇到了问题。为我提供了一个可以遵循的框架,但是我认为我可能会误会了一步。这是我所拥有的:
function img = sampleFBP(sino,angs)
% 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');
% 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
% 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(floor(diagDim/2), :) = fourierCurRow;
imContrib = imContrib * 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)));
我输入的正弦图只是Shepp-Logan体模上0到179度之间的radon函数的输出。现在按原样运行代码会给我黑色的图像。我认为我在循环中丢失了一些东西,在该循环中我向图像添加了行的FT。根据我对中心切片定理的理解,我认为应该发生的事情是:
初始化一个与2DFT大小相同的数组(即diagDim x diagDim)。这是傅立叶空间。
从单个角度获取与线积分信息相对应的正弦图的一行,并对其应用1D FT
根据中央切片定理,此线积分的FT是通过傅立叶域的线,该线以与投影采用的角度相对应的角度穿过原点。因此,为了模拟这一点,我将线的FT取整并将其放置在我创建的diagDim x diagDim矩阵的中心行中
接下来,我将创建的一维斜波滤波器的FT乘以线积分的FT。傅立叶域中的乘法等效于空间域中的卷积,因此这会使线与滤波器进行卷积。
现在,我将整个矩阵旋转投影所采用的角度。这应该给我一个diagDim x diagDim矩阵,其中一条信息线以一定角度穿过中心。Matlab旋转时会增加矩阵的大小,但是由于正弦图是在开始时填充的,因此不会丢失任何信息,并且仍然可以添加矩阵
如果将所有这些空矩阵与通过中心的一行相加在一起,则应该为我提供图像的完整2D FT。所有需要做的就是逆2D FT,原始图像应该是结果。
如果我遇到的问题是概念上的问题,那么如果有人可以指出我的问题所在,我将不胜感激。相反,如果这是Matlab的东西(我还是Matlab的新手),我会很高兴了解到我错过的东西。
您发布的代码是过滤反投影(FBP)的一个很好的示例,我认为这对于想学习FBP基础的人可能有用。可以使用iradon(...)
MATLAB中的函数(请参见此处)通过多种过滤器执行FBP。当然,在您的情况下,重点是学习中心切片定理的基础,因此找到捷径不是重点。通过回答您的问题,我也学到了很多东西,并刷新了我的知识!
现在,您的代码已被完美注释,并描述了需要采取的步骤。有一些微妙的[编程]问题需要解决,以使代码正常工作。
首先,由于floor(diagDim/2)
正弦图的大小,傅立叶域中的图像表示可能最终会缺少数组。我将其更改为round(diagDim/2)
在中具有完整的数据集fimg
。请注意,如果处理不当,可能会导致某些正弦图尺寸错误。我鼓励您可视化fimg
以了解缺少的数组是什么以及为什么重要。
第二个问题是,您的正弦图需要进行转置才能与算法保持一致。因此增加了sino = sino'
。再次,我鼓励您尝试在没有此代码的情况下尝试代码,以查看会发生什么!请注意,必须沿视图进行零填充,以避免因混叠而产生假象。我将在此答案中演示一个示例。
第三也是最重要的一点imContrib
是沿的数组的临时持有人fimg
。因此,它必须保持与相同的大小fimg
,因此
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的域分解为频率内容,例如时间,空间等)。
现在是一个完整的示例,以显示使用修改后的Shepp-Logan幻像的工作方式:
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');
),则这是同一张图片:
请注意,在有和没有零填充的情况下,重建图像中的对象大小不同。当正弦图填充为零时,对象会收缩,因为会压缩径向内容。
这几乎是一个很好的答案。但是,您要在频域中定义斜坡滤波器,然后计算其FFT并乘以投影的FFT,就好像您在空间域中定义了滤波器一样!删除该
fft
呼叫,结果实际上是正确的。您会注意到重建的图像将如何与输入体模更加相似。为了澄清,它必须是fourierCurRow' .* rampFilter_1d
。您似乎也混在一起,
round
并且floor
在代码中似乎忘记了替换floor
您所描述的某些代码。现在,这是一个很好的答案!;)感谢您修复这些问题。
感谢@CrisLuengo的出色提示。我相应地更新了我的答案。我也注意到我的零填充沿错误的尺寸。现在,重建的图像非常漂亮:)