How to gauss-filter (blur) a floating point numpy array

Question:

I have got a numpy array a of type float64. How can I blur this data with a Gauss filter?

I have tried

from PIL import Image, ImageFilter

image = Image.fromarray(a)
filtered = image.filter(ImageFilter.GaussianBlur(radius=7))

, but this yields ValueError: 'image has wrong mode'. (It has mode F.)

I could create an image of suitable mode by multiplying a with some constant, then rounding to integer. That should work, but I would like to have a more direct way.

(I am using Pillow 2.7.0.)

Asked By: Robert Pollak

||

Answers:

If you have a two-dimensional numpy array a, you can use a Gaussian filter on it directly without using Pillow to convert it to an image first. scipy has a function gaussian_filter that does the same.

from scipy.ndimage.filters import gaussian_filter

blurred = gaussian_filter(a, sigma=7)
Answered By: Carsten

Here is my approach using only numpy.
It is prepared with a simple 3×3 kernel, minor changes could make it work with custom sized kernels.

def blur(a):
    kernel = np.array([[1.0,2.0,1.0], [2.0,4.0,2.0], [1.0,2.0,1.0]])
    kernel = kernel / np.sum(kernel)
    arraylist = []
    for y in range(3):
        temparray = np.copy(a)
        temparray = np.roll(temparray, y - 1, axis=0)
        for x in range(3):
            temparray_X = np.copy(temparray)
            temparray_X = np.roll(temparray_X, x - 1, axis=1)*kernel[y,x]
            arraylist.append(temparray_X)

    arraylist = np.array(arraylist)
    arraylist_sum = np.sum(arraylist, axis=0)
    return arraylist_sum
Answered By: Filipe Alves

Purely numpy solution using convolve and the separability of the Gaussian filter into two separate filter steps (which makes it relatively fast):

kernel = np.array([1.0,2.0,1.0]) # Here you would insert your actual kernel of any size
a = np.apply_along_axis(lambda x: np.convolve(x, kernel, mode='same'), 0, a)
a= np.apply_along_axis(lambda x: np.convolve(x, kernel, mode='same'), 1, a)
Answered By: Thomas

My take on how to do this with open-cv (cv2)

I am using a Kernel size of (3, 3) make sure to adjust to your needs.
More details on configuration possibilities and more solutions with openCV are to be found here.

import cv2  # pip install opencv-python
image = cv2.GaussianBlur(image, (3, 3), cv2.BORDER_DEFAULT)
Answered By: mrk