【问题标题】:Majority filter Numpy array多数过滤器 Numpy 数组
【发布时间】:2019-07-07 13:13:19
【问题描述】:

我有一个由零、一和 NaN 组成的 numpy ndarray。我想在该数组上使用多数过滤器,这意味着我想设置一个内核窗口(例如,3X3 单元格),它将遍历数组并将中心单元格的值更改为发生的值在它的邻居中最多。这个过滤器应该维持两个约束,它应该忽略 NaN,如果中心单元的值为 1,那么它应该保持它为 1。

这是我正在寻找的一个小例子: 输入数组:

array([[ 1.,  1.,  1.,  0.,  0.],
       [ 1.,  1., nan,  1.,  1.],
       [nan,  1.,  1.,  0.,  1.],
       [ 0.,  0.,  0.,  0.,  1.]])

应用多数过滤器 输出数组:

array([[ 1.,  1.,  1.,  1.,  1.],
       [ 1.,  1., nan,  1.,  1.],
       [nan,  1.,  1.,  1.,  1.],
       [ 0.,  0.,  0.,  1.,  1.]])

我在看scipy filters,但找不到任何合适的东西。我想建立一个generic convolved filter,但我不确定如何为大多数目的做到这一点。感觉这是应该存在的退出基本过滤器,但我似乎找不到它。

【问题讨论】:

  • 您可能会发现这很有帮助stackoverflow.com/questions/41190852/…
  • 我在这里做了几种方法...stackoverflow.com/a/54440152/2836621
  • 为什么元素[1, -1](第二行最后一列)是1?看起来输入数组中这个元素的大多数邻居都是 0。
  • @AGNGazer,如我发布的问题中所述,如果值为 1(一),则无论其邻居如何,它都应保持为 1(一)

标签: python numpy filter scipy numpy-ndarray


【解决方案1】:

这是一个基于convolution 的矢量化想法。鉴于这些限制,我们似乎只需要编辑0s 地点。对于每个滑动窗口,获取 1 的计数,然后获取非 NaN,这决定了确定 1 是否为多数的阈值。如果是,则将那些也是 0 的地方设置为 1。

实现看起来像这样 -

from scipy.signal import convolve2d

def fill0s(a):
    # Mask of NaNs
    nan_mask = np.isnan(a)

    # Convolution kernel
    k = np.ones((3,3),dtype=int)

    # Get count of 1s for each kernel window
    ones_count = convolve2d(np.where(nan_mask,0,a),k,'same')

    # Get count of elements per window and hence non NaNs count
    n_elem = convolve2d(np.ones(a.shape,dtype=int),k,'same')
    nonNaNs_count = n_elem - convolve2d(nan_mask,k,'same')

    # Compare 1s count against half of nonNaNs_count for the first mask.
    # This tells us if 1s are majority among non-NaNs population.
    # Second mask would be of 0s in a. Use Combined mask to set 1s.
    final_mask = (ones_count >= nonNaNs_count/2.0) & (a==0)
    return np.where(final_mask,1,a)

请注意,由于我们使用这种 1s 内核执行统一过滤,因此我们也可以使用 uniform_filter。

示例运行 -

In [232]: a
Out[232]: 
array([[ 1.,  1.,  1.,  0.,  0.],
       [ 1.,  1., nan,  1.,  1.],
       [nan,  1.,  1.,  0.,  1.],
       [ 0.,  0.,  0.,  0.,  1.]])

In [233]: fill0s(a)
Out[233]: 
array([[ 1.,  1.,  1.,  1.,  1.],
       [ 1.,  1., nan,  1.,  1.],
       [nan,  1.,  1.,  1.,  1.],
       [ 0.,  0.,  0.,  1.,  1.]])

【讨论】:

  • 不错的解决方案,所以我想没有内置的多数过滤器,它需要构建。统一过滤器是什么意思?因为内核中的所有值都是 1?
  • @user88484 是的,因为都是 1,所以使用 uniform 我们将实现相同的效果。而且肯定没有内置的。
【解决方案2】:

试试下面的代码:

请注意,由于多个索引具有相同最大值时 numpy.argmax 的行为,结果与您的结果有些不同(您可能想编写自己的 argmax 函数... x=np.argwhere(x ==np.max(x))[:,0] 给出所有索引而不是只给出第一个)

import numpy as np

def block_fn(x,center_val):

    unique_elements, counts_elements = np.unique(x.ravel(), return_counts=True)

    if np.isnan(center_val):
        return np.nan
    elif center_val == 1:
        return 1.0
    else:
        return unique_elements[np.argmax(counts_elements)]



def majority_filter(x,block_size = (3,3)):

    #Odd block sizes only  ( ? )
    assert(block_size[0]%2 != 0 and block_size[1]%2 !=0)

    yy =int((block_size[0]-1)/2)
    xx =int((block_size[1]-1)/2)


    output= np.zeros_like(x)
    for i in range(0,x.shape[0]):
        miny,maxy = max(0,i-yy),min(x.shape[0]-1,i+yy)

        for j in range(0,x.shape[1]):
            minx,maxx = max(0,j-xx),min(x.shape[1]-1,j+xx)

            #Extract block to take majority filter over
            block=x[miny:maxy+1,minx:maxx+1]

            output[i,j] = block_fn(block,center_val=x[i,j])


    return output


inp=np.array([[ 1.,  1.,  1.,  0.,  0.],
       [ 1.,  1., np.nan,  1.,  1.],
       [np.nan,  1.,  1.,  0.,  1.],
       [ 0.,  0.,  0.,  0.,  1.]])


print(majority_filter(inp))

【讨论】:

    猜你喜欢
    • 2021-07-05
    • 2019-01-31
    • 2020-02-13
    • 1970-01-01
    • 1970-01-01
    • 2018-06-01
    • 1970-01-01
    相关资源
    最近更新 更多