简体   繁体   English

如何在不使用 for 循环的情况下填充二维二进制 Numpy 数组?

[英]How to fill 2D binary Numpy array without using for loop?

Suppose I have a Numpy array a and I want to fill the inner with all 1 like array b假设我有一个 Numpy 数组a并且我想像数组b一样用所有 1 填充内部

print(a)
array([[0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 1., 1., 1., 1., 1., 0., 0., 0.],
       [0., 1., 0., 1., 1., 1., 1., 1., 0., 0.],
       [0., 1., 0., 0., 1., 0., 0., 0., 1., 0.],
       [0., 1., 0., 1., 0., 0., 0., 0., 1., 0.],
       [0., 1., 0., 1., 0., 0., 0., 1., 0., 0.],
       [0., 1., 0., 1., 0., 0., 0., 1., 0., 0.],
       [0., 0., 1., 0., 0., 0., 0., 1., 0., 0.],
       [0., 0., 0., 1., 1., 1., 1., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]])

print(b)
array([[0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 1., 1., 1., 1., 1., 0., 0., 0.],
       [0., 1., 1., 1., 1., 1., 1., 1., 0., 0.],
       [0., 1., 1., 1., 1., 1., 1., 1., 1., 0.],
       [0., 1., 1., 1., 1., 1., 1., 1., 1., 0.],
       [0., 1., 1., 1., 1., 1., 1., 1., 0., 0.],
       [0., 1., 1., 1., 1., 1., 1., 1., 0., 0.],
       [0., 0., 1., 1., 1., 1., 1., 1., 0., 0.],
       [0., 0., 0., 1., 1., 1., 1., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]])

I'm currently using the for loop to do this, are there any ways to do this without using the for loop and only using Numpy?我目前正在使用for循环来执行此操作,是否有任何方法可以在使用for循环且使用 Numpy 的情况下执行此操作? Thanks.谢谢。

b = np.zeros(a.shape)
for i in range(a.shape[0]):
    occupied = np.where(a[i] == 1)[0]
    if len(occupied) > 0:
        for j in range(occupied[0], occupied[-1] + 1):
            b[i][j] = 1

Edit :编辑

  • Only using Numpy仅使用 Numpy
  • The areas I want to fill always have contiguous boundaries.我要填充的区域总是有连续的边界。

Can you use scipy?您可以使用 scipy 吗? Do the areas you want to fill always have contiguous boundaries?您要填充的区域是否始终具有连续的边界?

In [1]: from scipy import ndimage

In [2]: # x = ... copied from OP

In [3]: ndimage.binary_fill_holes(x).astype(int)
Out[3]:
array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
       [0, 0, 1, 1, 1, 1, 1, 0, 0, 0],
       [0, 1, 1, 1, 1, 1, 1, 1, 0, 0],
       [0, 1, 1, 1, 1, 1, 1, 1, 1, 0],
       [0, 1, 1, 1, 1, 1, 1, 1, 1, 0],
       [0, 1, 1, 1, 1, 1, 1, 1, 0, 0],
       [0, 1, 1, 1, 1, 1, 1, 1, 0, 0],
       [0, 0, 1, 1, 1, 1, 1, 1, 0, 0],
       [0, 0, 0, 1, 1, 1, 1, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])

This is one way to achieve everything in numpy.这是实现 numpy 中所有内容的一种方法。

def dilation(x):
    out = x.copy()
    # Get mask of non-zeros and then use it to forward-filled indices
    r, c = x.nonzero()
    bins = np.bincount(r)
    indices = np.cumsum(bins)
    col_slices = np.split(c, indices)
    row_slices = np.split(r, indices)    
    for rw, cl in zip(row_slices, col_slices):
        if cl.size !=0:
            out[rw[0], cl[0]:cl[-1]] = 1
    return out

We can acheive further speed up by changing the last for loop to list comprehesion.我们可以通过将最后一个 for 循环更改为列表理解来进一步加快速度。 It doesn't delegate the work to underlying C but the assembly code generated is shorter than normal for loop and hence faster.它不会将工作委托给底层 C,但生成的汇编代码比正常的 for 循环更短,因此速度更快。

def assign_val(out, rw, cl):
    out[rw[0], cl[0]:cl[-1]] = 1

def dilation(x):
    out = x.copy()
    # Get mask of non-zeros and then use it to forward-filled indices
    r, c = x.nonzero()
    bins = np.bincount(r)
    indices = np.cumsum(bins)
    col_slices = np.split(c, indices)
    row_slices = np.split(r, indices)    
    [assign_val(out, rw, cl) for rw, cl in zip(row_slices, col_slices) if cl.size !=0]
    return out

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

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