简体   繁体   中英

Why image is shifted when using ifft2 in Matlab

I'm implementing 2-D convolution by using FFT. Here is my code:

img = im2single(imread('dog.bmp'));
filter = fspecial('gaussian', 53, 3);
F = fft2(img);
mask = fft2(filter, size(img, 1), size(img, 2));
filtered_img = ifft2(F .* mask);
imshow(real(filtered_img));

Here is the original image:

在此处输入图像描述

The result is here: 在此处输入图像描述

Why does this happen? How can I fix it? Please help me. Many thanks.

The problem is that the frequency response of your filter,

filter = fspecial('gaussian', 53, 3);

is shifted with respect to the origin of coordinates. To check this, use

imagesc(filter)

在此处输入图像描述

You can see that filter has its maximum at coordinates 27 , 27 , not 1 , 1 . The amount of shift can be computed (for odd-sized impulse response) as (size(filter)-1)/2 , which in this case gives [26, 26] .

In the following, I'll use this image as an example:

img = im2single(imread('cameraman.tif')); % size [256, 256]

Later in your code, when you call fft2 with the optional second and third arguments,

mask = fft2(filter, size(img, 1), size(img, 2));

the first input is implicitly right- padded with zeros in each dimension to match the specified size, which is 256 for my example img . You can check this by plotting its inverse transform:

imagesc(real(ifft2(mask)))

在此处输入图像描述


After that, your code multiplies the transforms of the original image and the impulse response of the filter, and then transforms back. That's equivalent to a circular convolution of the original image img and the impulse response filter . Now, since the latter is shifted by 26 samples with respect to the origin in both dimensions, that produces a circular shift in the output signal. This is the problem you observe.


To solve this, you need to correct for the shifting, while taking into account the padding.

The simplest way is to manually do the padding (instead of letting fft2 do it implicitly) and at the same time circularly shift (size(filter)-1)/2 samples to the left in each dimension:

filter_corrected = filter; % initiallize
filter_corrected(size(img, 1), size(img, 2)) = 0; % this right-pads with zeros
shift = (size(filter)-1)/2; % as seen above
filter_corrected = filter_corrected( ...
    mod((1:end)+shift(1)-1, end)+1, ...
    mod((1:end)+shift(2)-1, end)+1); % this undoes the circular shifting

Now the corrected impulse response, filter_corrected , has the required size and its maximum is at 1 , 1 (although it's hard to observe in the example):

imagesc(filter_corrected)

在此处输入图像描述

So you can use filter_corrected in the rest of your code:

F = fft2(img);
mask = fft2(filter_corrected, size(img, 1), size(img, 2));
filtered_img = ifft2(F .* mask);
imshow(real(filtered_img));

With this, the original and filtered images are

imshow(img)
figure
imshow(real(filtered_img))

在此处输入图像描述

在此处输入图像描述


As additional notes ,

  • Observe how the filtering process causes a little bit of the lower part of the image (legs of the cameraman) to "spill" into the upper part. This is a consequence of the method you use for filtering, namely multiplying in the DFT domain, which corresponds to circular convolution in the original domain.
  • It's better not to use filter as a variable name, because that shadows the built-in function with the same name.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM