首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Numpy滤波器平滑零区域

Numpy滤波器平滑零区域
EN

Stack Overflow用户
提问于 2017-09-09 01:39:38
回答 3查看 969关注 0票数 3

我有一个由ints 0和更高版本组成的2D numpy数组,其中的值表示区域标签。例如,

代码语言:javascript
运行
复制
array([[9, 9, 9, 0, 0, 0, 0, 1, 1, 1],
       [9, 9, 9, 9, 0, 7, 1, 1, 1, 1],
       [9, 9, 9, 9, 0, 2, 2, 1, 1, 1],
       [9, 9, 9, 8, 0, 2, 2, 1, 1, 1],
       [9, 9, 9, 8, 0, 2, 2, 2, 1, 1],
       [4, 4, 4, 4, 0, 2, 2, 2, 1, 1],
       [4, 6, 6, 4, 0, 0, 0, 0, 0, 0],
       [4, 6, 6, 4, 0, 0, 0, 0, 0, 0],
       [4, 4, 4, 4, 5, 5, 5, 5, 5, 5],
       [4, 4, 4, 4, 5, 5, 5, 5, 5, 5]])

我希望指数等于0(即零区域),取其邻域中最常见的值。操作基本上会关闭零区域。我尝试过多种不同的扩展、侵蚀、灰色闭包和其他形态学运算,但我不能完全消除零区域(不尴尬地混合其他区域)。一种很好的方法是定义一个内核,它只在零的基础上转换,并使用过滤器区域中最常见的标签来设置值。不过,我不知道如何实现这一点。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2017-09-09 05:36:44

本文提出了一种矢量化方法。步骤如下:

  1. 获取内核大小的2D滑动窗口,导致4D数组。我们可以使用skimage's view_as_windows获取这些视图,从而避免为此创建任何额外的内存。
  2. 通过索引到4D数组,选择以零为中心的窗口。这会强制复制一份。但是,假设零的数目比输入数组中的元素总数要小,这应该是可以的。
  3. 对于所选的每个窗口,使用适当的偏移量来偏移每个窗口,并使用np.bincount来执行计数。因此,使用bincount并获得除去零的最大计数。最大计数的争论应该是我们的人!

以下是这些步骤的实现-

代码语言:javascript
运行
复制
from skimage.util import view_as_windows as viewW

def fill_zero_regions(a, kernel_size=3):
    hk = kernel_size//2 # half_kernel_size    

    a4D = viewW(a, (kernel_size,kernel_size))
    sliced_a = a[hk:-hk,hk:-hk]
    zeros_mask = sliced_a==0
    zero_neighs = a4D[zeros_mask].reshape(-1,kernel_size**2)
    n = len(zero_neighs) # num_zeros

    scale = zero_neighs.max()+1
    zno = zero_neighs + scale*np.arange(n)[:,None] # zero_neighs_offsetted

    count = np.bincount(zno.ravel(), minlength=n*scale).reshape(n,-1)
    modevals = count[:,1:].argmax(1)+1
    sliced_a[zeros_mask] = modevals
    return a

样本运行-

代码语言:javascript
运行
复制
In [23]: a
Out[23]: 
array([[9, 9, 9, 0, 0, 0, 0, 1, 1, 1],
       [9, 9, 9, 9, 0, 7, 1, 1, 1, 1],
       [9, 9, 9, 9, 0, 2, 2, 1, 1, 1],
       [9, 9, 9, 8, 0, 2, 2, 1, 1, 1],
       [9, 9, 9, 8, 0, 2, 2, 2, 1, 1],
       [4, 4, 4, 4, 0, 2, 2, 2, 1, 1],
       [4, 6, 6, 4, 0, 0, 0, 0, 0, 0],
       [4, 6, 6, 4, 0, 0, 0, 0, 0, 0],
       [4, 4, 4, 4, 5, 5, 5, 5, 5, 5],
       [4, 4, 4, 4, 5, 5, 5, 5, 5, 5]])

In [24]: fill_zero_regions(a)
Out[24]: 
array([[9, 9, 9, 0, 0, 0, 0, 1, 1, 1],
       [9, 9, 9, 9, 9, 7, 1, 1, 1, 1],
       [9, 9, 9, 9, 2, 2, 2, 1, 1, 1],
       [9, 9, 9, 8, 2, 2, 2, 1, 1, 1],
       [9, 9, 9, 8, 2, 2, 2, 2, 1, 1],
       [4, 4, 4, 4, 2, 2, 2, 2, 1, 1],
       [4, 6, 6, 4, 4, 2, 2, 2, 1, 0],
       [4, 6, 6, 4, 4, 5, 5, 5, 5, 0],
       [4, 4, 4, 4, 5, 5, 5, 5, 5, 5],
       [4, 4, 4, 4, 5, 5, 5, 5, 5, 5]])

正如我们所看到的,我们并不是在解决边界问题。如果需要的话,使用一个零填充数组作为输入数组,如下所示:np.pad(a, (k//2,k//2), 'constant'),以k作为内核大小(示例的=3)。

票数 1
EN

Stack Overflow用户

发布于 2017-09-09 02:23:43

基于卷积思想的一种可能的解决方案

代码语言:javascript
运行
复制
from scipy import stats
ar = #Your np array
blank = np.zeros(ar.shape)
#Size to search in for mode values
window_size = 3

for x,y in np.array(np.where(ar == 0)).T:
    window = ar[max(x-window_size,0):x+window_size,max(0,y-window_size):y+window_size]
    oneD = window.flatten()

    #fill blank array with modal value
    blank[x,y] = stats.mode(oneD[oneD != 0])[0]

#fill in the zeros
print ar + blank

我不确定这里是否有可能避免一个循环

票数 0
EN

Stack Overflow用户

发布于 2017-09-09 02:47:35

这里有一个使用Numba的工作解决方案,我还没有描述它,但是应该非常快:

代码语言:javascript
运行
复制
import numba
@numba.njit
def nn(arr):
    res = arr.copy()
    zeros = np.where(arr == 0)
    for n in range(len(zeros[0])):
        i = zeros[0][n]
        j = zeros[1][n]
        left = max(i-1, 0)
        right = min(i+2, arr.shape[1])
        top = max(j-1, 0)
        bottom = min(j+2, arr.shape[0])
        area = arr[left:right,top:bottom].ravel()
        counts = np.bincount(area[area != 0])
        res[i,j] = np.argmax(counts)
    return res

它产生:

代码语言:javascript
运行
复制
array([[9, 9, 9, 9, 7, 1, 1, 1, 1, 1],
       [9, 9, 9, 9, 9, 7, 1, 1, 1, 1],
       [9, 9, 9, 9, 2, 2, 2, 1, 1, 1],
       [9, 9, 9, 8, 2, 2, 2, 1, 1, 1],
       [9, 9, 9, 8, 2, 2, 2, 2, 1, 1],
       [4, 4, 4, 4, 2, 2, 2, 2, 1, 1],
       [4, 6, 6, 4, 4, 2, 2, 2, 1, 1],
       [4, 6, 6, 4, 4, 5, 5, 5, 5, 5],
       [4, 4, 4, 4, 5, 5, 5, 5, 5, 5],
       [4, 4, 4, 4, 5, 5, 5, 5, 5, 5]])

这里的内核大小是3x3,通过将1减去1并将2添加到ij (添加2是因为Python片需要一个过端,例如0:3给出了3个元素)。边界条件由minmax处理。

二进制计数思想的功劳:https://stackoverflow.com/a/6252400/4323

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/46126409

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档