3d数组上的ndimage.generic_function

时间:2016-04-07 06:23:05

标签: python numpy scipy convolution

我需要根据邻居值和自身计算矩阵中最常见的元素。我找到了一个generic_filter函数,我用它来计算我想要的东西。所以这就是我如何为二维数组做到这一点

arr = np.array([
    [1, 2, 4],
    [5, 6, 7],
    [2, 4, 4]
])

def most_frequent(arr):
    def most_frequent(val):
        return Counter(val).most_common(1)[0][0]

    footprint = [[1, 1, 1], [1, 1, 1], [1, 1, 1]]
    return ndimage.generic_filter(arr, most_frequent, footprint=footprint, mode='constant')

print most_frequent(arr)

这会让我回头

[[0 0 0]
 [0 4 0]
 [0 0 0]]

忽略边缘上的元素。如您所见,中间元素为4,因为这是邻居和值中最常见的元素。

最大的问题是我需要为3d矩阵做同样的事情。所以对于像这样的矩阵

arr = np.array([
    [[1, 1], [2, 2], [4, 4]],
    [[5, 5], [6, 6], [7, 7]],
    [[2, 2], [4, 4], [4, 4]]
])

我希望到处都有[0, 0],中间有[4, 4]。这与RuntimeError('filter footprint array has incorrect shape.')失败。更糟糕的是,我怀疑我可以在这里使用generic_filter,因为文档说:

  

cval:scalar,optional如果模式为,则填充输入的过去边缘的值   “恒定”。

那么如何解决我的问题?

2 个答案:

答案 0 :(得分:1)

这是一个完全向量化的解决方案。

首先做平坦的社区:

(n,m,_)=M.shape 
(sn,sm,s2)=M.strides 
newshape=(n-2,m-2,9,2)
newstrides=(sn,sm,2*s2,s2)
neighborhoods=np.lib.stride_tricks.as_strided(M,newshape,newstrides)
"""
array([[[[1, 1],
         [2, 2],
         [4, 1],
         [1, 1],
         [5, 5],
         [6, 6],
         [7, 7],
         [2, 3],
         [2, 2]],

        [[2, 2],
         [4, 1],
         [1, 1],
         [5, 5],
         [6, 6],
         [7, 7],
         [2, 3],
         [2, 2],
         [4, 1]]]])
     """

然后你必须打包这两个组件才能使用{1}来处理1D数组。 假设np.unique是int32,您可以通过视图执行此操作:

M.dtype

现在我们定义一个函数,该函数采用一维数组并根据packed_neighborhoods=np.ascontiguousarray(neighborhoods).view(int64) In [5]: packed_neighborhoods.shape Out[5]: (1, 2, 9, 1) 找到最常见的指数:

np.unique

将它应用于好轴:

def mostfreq(arr):
     _,index,counts=unique(arr, return_index=True, return_counts=True)
     return index[counts.argmax()]

结果包括其他指数。

ind2=apply_along_axis(mostfreq,2,packed_neighborhoods).squeeze()

但是你的解决方案目前具有相同的性能;(。

答案 1 :(得分:0)

我发现如何实现这一目标的一种方法是做类似

的事情
def most_frequent(M):
    x, y, _ = arr.shape
    res = np.zeros((x - 2, y - 2, 2))
    for i in xrange(1, x - 1):
        for j in xrange(1, y - 1):
            neighbors = [M[i - 1, j - 1], M[i - 1, j], M[i - 1, j + 1], M[i, j - 1], M[i, j], M[i, j + 1], M[i + 1, j - 1], M[i + 1, j], M[i + 1, j + 1]]
            res[i - 1, j - 1] = Counter([tuple(_) for _ in neighbors]).most_common(1)[0][0]

    return res

仍在寻找更好的解决方案(不涉及我的2个循环的解决方案)。