2
$\begingroup$

I'm trying to do an FFT-based gaussian blur on a grayscale image, and it works, however it seems to introduce ringing artifacts to the result when compared to the expected direct filter. What can I do to mitigate this?

In reality I'm using quite a wide gaussian kernel, so I'd rather not use direct convolution for the blurring.

Example:

direct vs FFT-based gaussian filters

The left image is a regular blur, the right one is the FFT-based blur. Note the "ringing" especially in the top middle-left part of the right image. Also it seems like the blur is a bit stronger on the right for some reason.

(python) code:

import numpy as np
from scipy import ndimage, misc
import matplotlib.pyplot as plt

ascent = misc.ascent()[300:450, 100:250].astype(np.float64)

input_ = np.fft.rfft2(ascent)
result = ndimage.fourier_gaussian(input_, sigma=1.5)
result = np.fft.irfft2(result)

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(5, 2.5))
plt.tight_layout()

plt.gray()
ax1.imshow(ndimage.gaussian_filter(ascent, 1.5, mode='wrap', truncate=10))
ax2.imshow(result)

plt.savefig("fourier gaussian blur test.png")

I apologize if this question is trivial, I don't know much about image processing.

$\endgroup$
4
  • $\begingroup$ does the documentation of fourier_gaussian specify the size of the Gaussian kernel? (or, if it doesn't, what does the result look like when your input is a single white pixel against black background)? I suspect edge / windowing effects. $\endgroup$ Jun 26 at 18:34
  • $\begingroup$ though I must admit, I'm not really seeing ringing – I see a low-pass approximation of the original image, which has strong periodic components due to the vertical bars, so when you apply a low-pass filter, you'll kill the high-frequency components that make this looks like dark, well-defined bars before a light background and are left with the fundamental sines. $\endgroup$ Jun 26 at 18:42
  • $\begingroup$ @MarcusMüller It looks like this. Very noticeable artifacts but only in one direction $\endgroup$ Jun 26 at 18:42
  • $\begingroup$ ah excellent! Yeah, this means the thing is assuming wrong FFT type/size in one direction; Cris is right! $\endgroup$ Jun 26 at 23:08
2
$\begingroup$

You should read the documentation for the function you’re using:

n: int, optional
If n is negative (default), then the input is assumed to be the result of a complex fft. If n is larger than or equal to zero, the input is assumed to be the result of a real fft, and n gives the length of the array before transformation along the real transform direction.

This means that you should either use the normal fft2, which produces a complex-valued result, or you should set the n argument to the filter function so it knows that the array you pass in is the result of rff2. Note that for rfft the output has a different size than the input (it returns half the array), and that there is an odd-sized input that produces the same size output as any given even-sized input. So with rfft2 it is important to remember the size of the original image. You will have to pass it to irfft2 as well.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.