I wonder if anyone could help me extend the smoothing example in the SciPy cookbook to a 2D problem.
This script works great for smoothing a 1D function, and they also give code for a 2D smoothing in both axis (i.e. blurring an image).
However, I'd like to apply this function to a 2D dataset, but only along one axis (x direction). I could do this in a loop, by inspecting each slice in y, applying the 1D convolution, then rebuilding the array. But this seems poor coding technique.
Therefore, I wonder how to do it in 2D? I imagine I need to make a 2D kernel with weights changing along one direction only, but I'm not sure how to do this, or which convolve function to use (numpy.convolve
, scipy.signal.convolve
, scipy.ndimage.filters.convolve1d
etc.)
Perhaps the simplest option is to use one of the 1D filters in scipy.ndimage.filters
:
from scipy import ndimage
from scipy.misc import lena
img = lena()
# a uniform (boxcar) filter with a width of 50
boxcar = ndimage.uniform_filter1d(img, 50, 1)
# a Gaussian filter with a standard deviation of 10
gauss = ndimage.gaussian_filter1d(img, 10, 1)
You could also use the non-1D versions of the filters like this: ndimage.gaussian_filter(img, (0, 10))
(i.e. set the filter width to 0 for the axes that you don't want to smooth along).
To smooth with an arbitrary kernel, you could use scipy.ndimage.convolve1d
:
import numpy as np
kern = np.hanning(50) # a Hanning window with width 50
kern /= kern.sum() # normalize the kernel weights to sum to 1
hanning = ndimage.convolve1d(img, kern, 1)
Here's what the various outputs look like:
from matplotlib import pyplot as plt
fig, ax = plt.subplots(2, 2, figsize=(8, 8))
ax[0, 0].imshow(img)
ax[0, 0].set_title('Original')
ax[0, 1].imshow(boxcar)
ax[0, 1].set_title('Boxcar filter (width = 50)')
ax[1, 0].imshow(gauss)
ax[1, 0].set_title(r'Gaussian filter ($\sigma$ = 10)')
ax[1, 1].imshow(hanning)
ax[1, 1].set_title(r'Hanning window (width = 50)')
for aa in ax.flat:
aa.set_axis_off()
fig.tight_layout()
plt.show()