Frequency domain filtering with scipy.fftpack, iff

2019-02-20 09:41发布

问题:

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:

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.

回答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:

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.