Reputation: 175
Starting with a 2d array of 0s and 1s, I need to identify which 1s form a united fence completely enclosing one or more adjacent 0s. Those 0s are considered adjacent if they touch on their sides or the diagonal. The fence must exist on the neighboring diagonal as well.
This is the 2d array, and what I want are the 1s which indicate the fence, and then everything else should be zero. This is a simple case, in reality the array is a png image, and I want all the fences that may exist in it.
Is ndimage the module needed? Any advice please.
array=
[[1,1,1,1,1,1],
[1,1,0,0,1,1],
[1,1,0,1,1,1],
[1,1,1,1,1,1],
[0,0,1,1,0,0]]
answer=
[[0,1,1,1,1,0],
[0,1,0,0,1,0],
[0,1,0,1,1,0],
[0,1,1,1,0,0],
[0,0,0,0,0,0]]
Upvotes: 4
Views: 65
Reputation: 2013
Following the approach suggested by Jerome and Mark:
from collections import deque as queue
from scipy import ndimage
import numpy as np
from skimage.segmentation import flood_fill
A = np.array([[1,1,1,1,1,1],
[1,1,0,0,1,1],
[1,1,0,1,1,1],
[1,1,1,1,1,1],
[0,0,1,1,0,0]])
A = np.pad(A, pad_width=1, mode='constant', constant_values=0)
print("A after padding")
print(A)
A = flood_fill(A, (0, 0), 1)
print("A after flooding")
print(A)
# you can also use cv2.dilate if you want to avoid ndimage
struct2 = ndimage.generate_binary_structure(2, 2)
B = ndimage.binary_dilation(1-A, structure=struct2).astype(A.dtype)
print("B")
print(B)
print("result")
res = B & A
print(res[1:-1, 1:-1]) # remove padding
Output:
A after padding
[[0 0 0 0 0 0 0 0]
[0 1 1 1 1 1 1 0]
[0 1 1 0 0 1 1 0]
[0 1 1 0 1 1 1 0]
[0 1 1 1 1 1 1 0]
[0 0 0 1 1 0 0 0]
[0 0 0 0 0 0 0 0]]
A after BFS
[[1 1 1 1 1 1 1 1]
[1 1 1 1 1 1 1 1]
[1 1 1 0 0 1 1 1]
[1 1 1 0 1 1 1 1]
[1 1 1 1 1 1 1 1]
[1 1 1 1 1 1 1 1]
[1 1 1 1 1 1 1 1]]
B
[[0 0 0 0 0 0 0 0]
[0 0 1 1 1 1 0 0]
[0 0 1 1 1 1 0 0]
[0 0 1 1 1 1 0 0]
[0 0 1 1 1 0 0 0]
[0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0]]
result
[[0 1 1 1 1 0]
[0 1 0 0 1 0]
[0 1 0 1 1 0]
[0 1 1 1 0 0]
[0 0 0 0 0 0]]
Upvotes: 1