Search code examples
pythonimage-processingnumpyscipyndimage

Scipy filter with multi-dimensional (or non-scalar) output


Is there a filter similar to ndimage's generic_filter that supports vector output? I did not manage to make scipy.ndimage.filters.generic_filter return more than a scalar. Uncomment the line in the code below to get the error: TypeError: only length-1 arrays can be converted to Python scalars.

I'm looking for a generic filter that process 2D or 3D arrays and returns a vector at each point. Thus the output would have one added dimension. For the example below I'd expect something like this:

m.shape    # (10,10)
res.shape  # (10,10,2)

Example Code

import numpy as np
from scipy import ndimage

a = np.ones((10, 10)) * np.arange(10)

footprint = np.array([[1,1,1],
                    [1,0,1],
                    [1,1,1]])

def myfunc(x):
    r = sum(x)
    #r = np.array([1,1])  # uncomment this
    return r

res = ndimage.generic_filter(a, myfunc, footprint=footprint)

Solution

  • The generic_filter expects myfunc to return a scalar, never a vector. However, there is nothing that precludes myfunc from also adding information to, say, a list which is passed to myfunc as an extra argument.

    Instead of using the array returned by generic_filter, we can generate our vector-valued array by reshaping this list.


    For example,

    import numpy as np
    from scipy import ndimage
    
    a = np.ones((10, 10)) * np.arange(10)
    
    footprint = np.array([[1,1,1],
                          [1,0,1],
                          [1,1,1]])
    
    ndim = 2
    def myfunc(x, out):
        r = np.arange(ndim, dtype='float64')
        out.extend(r)
        return 0
    
    result = []
    ndimage.generic_filter(
        a, myfunc, footprint=footprint, extra_arguments=(result,))
    result = np.array(result).reshape(a.shape+(ndim,))