Suppose I have a Numpy array a
and I want to fill the inner with all 1 like array b
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? 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
- The areas I want to fill always have contiguous boundaries.
CodePudding user response:
Can you use 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]])
CodePudding user response:
This is one way to achieve everything in 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. It doesn't delegate the work to underlying C but the assembly code generated is shorter than normal for loop and hence faster.
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