我有一个由ints 0和更高版本组成的2D numpy数组,其中的值表示区域标签。例如,
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(即零区域),取其邻域中最常见的值。操作基本上会关闭零区域。我尝试过多种不同的扩展、侵蚀、灰色闭包和其他形态学运算,但我不能完全消除零区域(不尴尬地混合其他区域)。一种很好的方法是定义一个内核,它只在零的基础上转换,并使用过滤器区域中最常见的标签来设置值。不过,我不知道如何实现这一点。
发布于 2017-09-09 05:36:44
本文提出了一种矢量化方法。步骤如下:
skimage's view_as_windows
获取这些视图,从而避免为此创建任何额外的内存。np.bincount
来执行计数。因此,使用bincount
并获得除去零的最大计数。最大计数的争论应该是我们的人!以下是这些步骤的实现-
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
样本运行-
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
)。
发布于 2017-09-09 02:23:43
基于卷积思想的一种可能的解决方案
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
我不确定这里是否有可能避免一个循环
发布于 2017-09-09 02:47:35
这里有一个使用Numba的工作解决方案,我还没有描述它,但是应该非常快:
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
它产生:
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添加到i
和j
(添加2是因为Python片需要一个过端,例如0:3给出了3个元素)。边界条件由min
和max
处理。
二进制计数思想的功劳:https://stackoverflow.com/a/6252400/4323
https://stackoverflow.com/questions/46126409
复制相似问题