简体   繁体   English

多数过滤器 Numpy 数组

[英]Majority filter Numpy array

I have a numpy ndarray comprises of zeros, ones and NaNs.我有一个由零、一和 NaN 组成的 numpy ndarray。 I would like to use a majority filter on that array, meaning that I would like to set a kernel window (eg, 3X3 cells) that will go over the array and will change the value of the cell in the center to the value that occur the most in its neighbors.我想在该数组上使用多数过滤器,这意味着我想设置一个内核窗口(例如,3X3 单元格),它将遍历数组并将中心单元格的值更改为发生的值在其邻居中最多。 This filter should sustain two constrains, it should ignore NaNs and if the value of the center cell is one, then it should keep it one.这个过滤器应该维持两个约束,它应该忽略 NaN,如果中心单元格的值为 1,那么它应该保持为 1。

Here is a small example of what I'm looking for: input array:这是我正在寻找的一个小例子:输入数组:

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

Apply majority filter output array:应用多数过滤器输出数组:

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

I was looking at scipy filters but could not find anything adequate.我正在查看scipy 过滤器,但找不到任何足够的东西。 I thought to build a generic convolved filter , but I'm not sure how to do that for majority purpose.我想建立一个通用的卷积过滤器,但我不确定如何为大多数目的做到这一点。 It feels that this is quit basic filter that should be out there, but I can't seem to find it.感觉这是应该存在的基本过滤器,但我似乎找不到它。

Here's one vectorized idea based on convolution .这是一个基于convolution矢量化思想。 Given those constraints, it seems we need to edit only the 0s places.鉴于这些限制,我们似乎只需要编辑0s位。 For each sliding window, get count of 1s and then non-NaNs, which decides threshold for deciding if 1s are majority.对于每个滑动窗口,获取 1 的计数,然后是非 NaN,这决定了决定 1 是否为多数的阈值。 If they are, set those places that are also 0s as 1s.如果是,将那些也是 0 的地方设置为 1。

The implementation would look something like this -实现看起来像这样 -

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)

Note that since, we are performing uniform filtering with that kind of 1s kernel, we can also use uniform_filter .请注意,由于我们正在使用那种 1s 内核执行统一过滤,因此我们也可以使用uniform_filter

Sample run -样品运行 -

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.]])

Try the following code:试试下面的代码:

Note that the result is a bit different than yours, due to the behavior of numpy.argmax when multiple indices has the same maximum value (You might want to write your own argmax function... x=np.argwhere(x==np.max(x))[:,0] gives all the indices instead of only the first)请注意,结果与您的有点不同,这是由于 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))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM