Skip to content Skip to sidebar Skip to footer

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. Uncommen

Solution 1:

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,))

Solution 2:

I think I get what you're asking, but I'm not completely sure how does the ndimage.generic_filter work (how abstruse is the source!).

Here's just a simple wrapper function. This function will take in an array, all the parameters ndimage.generic_filter needs. Function returns an array where each element of the former array is now represented by an array with shape (2,), result of the function is stored as the second element of that array.

def generic_expand_filter(inarr, func, **kwargs):
    shape = inarr.shape
    res = np.empty((  shape+(2,) ))
    temp = ndimage.generic_filter(inarr, func, **kwargs)
    for row in range(shape[0]):
        for val in range(shape[1]):
            res[row][val][0] = inarr[row][val]
            res[row][val][1] = temp[row][val]
    return res

Output, where res denotes just the generic_filter and res2 denotes generic_expand_filter, of this function is:

>>> a.shape #same as res.shape
(10, 10)
>>> res2.shape
(10, 10, 2)

>>> a[0]
array([ 0.,  1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9.])
>>> res[0]
array([  3.,   8.,  16.,  24.,  32.,  40.,  48.,  56.,  64.,  69.])
>>> print(*res2[0], sep=", ") #this is just to avoid the vertical default output
[ 0.  3.], [ 1.  8.], [  2.  16.], [  3.  24.], [  4.  32.], [  5.  40.], [  6.  48.], [  7.  56.], [  8.  64.], [  9.  69.]

>>> a[0][0]
0.0
>>> res[0][0]
3.0
>>> res2[0][0]
array([ 0.,  3.])

Of course you probably don't want to save the old array, but instead have both fields as new results. Except I don't know what exactly you had in mind, if the two values you want stored are unrelated, just add a temp2 and func2 and call another generic_filter with the same **kwargs and store that as the first value.

However if you want an actual vector quantity that is calculated using multiple inarr elements, meaning that the two new created fields aren't independent, you are just going to have to write that kind of a function, one that takes in an array, idx, idy indices and returns a tuple\list\array value which you can then unpack and assign to the result.


Post a Comment for "Scipy Filter With Multi-dimensional (or Non-scalar) Output"