Frequency domain filtering with scipy.fftpack, ifft2 does not give the desired result
Frequency domain filtering with scipy.fftpack, ifft2 does not give the desired result
I am trying to simply apply a Gaussian filter on a gray-scale input lena image in frequency domain with the following code and here is the wrong output I am getting:
from scipy import signal
from skimage.io import imread
import scipy.fftpack as fp
import matplotlib.pyplot as plt
im = imread('lena.jpg') # read lena gray-scale image
# create a 2D-gaussian kernel with the same size of the image
kernel = np.outer(signal.gaussian(im.shape[0], 5), signal.gaussian(im.shape[1], 5))
freq = fp.fftshift(fp.fft2(im))
freq_kernel = fp.fftshift(fp.fft2(kernel))
convolved = freq*freq_kernel # simply multiply in the frequency domain
im_out = fp.ifft2(fp.ifftshift(convolved)).real # output blurred image
However, if I do the same but use signal.fftconvolve
I get the desired blurred image output as shown below:
signal.fftconvolve
im_out = signal.fftconvolve(im, kernel, mode='same') # output blurred image
My input image is 220x220, is there any padding issue? if so, how to solve it and make the first code (without fftconvolve
) work? any help will be highly appreciated.
fftconvolve
1 Answer
1
First of all, there is no need to shift the result of the FFT just to shift it back before doing the IFFT. This just amounts to a lot of shifting they has no effect on the result. Multiplying the two arrays happens in the same way whether you shift them both or not.
The problem you noticed in your output is that the four quadrants are swapped. The reason this happens is because the filter is shifted by half its size, causing the same shift in the output.
Why is it shifted? Well, because the FFT puts the origin in the top-left corner of the image. This is not only true for the output of the FFT, but also for its input. Thus, you need to generate a kernel whose origin is at the top-left corner. How? Simply apply ifftshift
to it before calling fft
:
ifftshift
fft
freq = fp.fft2(im)
freq_kernel = fp.fft2(fp.ifftshift(kernel))
convolved = freq*freq_kernel
im_out = fp.ifft2(convolved).real
Note that ifftshift
shifts the origin from the center to the top-left corner, whereas fftshift
shifts it from the corner to the center.
ifftshift
fftshift
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
Great answer, thank you very much.
– Sandipan Dey
Jul 6 at 5:54