1

I'm dealing with a problem which I handle a lot of shapes such as:

enter image description here enter image description here enter image description here enter image description here

These are represented as simple numpy arrays with 0 representing empty, and any other value representing not empty.

I need to fill the shapes which have empty interior spaces, such as the two squares above. But I haven't figured out any simple solution.

Any ideas or suggestions for packages?

schapke
  • 338
  • 2
  • 6
  • 1
    This seems like a problem of detecting and filling the bounding boxes. This might be helpful https://stackoverflow.com/questions/54638817/fill-bounding-boxes-in-2d-array/54675526#54675526 – yatu Mar 06 '20 at 11:21
  • You definitely can see the problem as such. Although, I think the more straight forward approach is to fill all empty values outside of the bounding boxes, and then if there is any empty values left they are the interior of a shape. I've taken a look in the post you referenced, but it didn't come up to me how to use it in this problem, what was your idea? – schapke Mar 06 '20 at 11:41
  • 1
    [`scipy.ndimage.binary_fill_holes`](https://docs.scipy.org/doc/scipy-1.4.1/reference/generated/scipy.ndimage.binary_fill_holes.html) might help, although if you have different numbers to signify different shapes, and you want to keep them separated, you may need to loop through the shape ids or something. – jdehesa Mar 06 '20 at 12:35
  • What do you mean by `fill` ? What do you want there instead of 0 ? What kind of continuity are you looking for ? For example on the first figure the hole at the top right ? – Liris Mar 06 '20 at 13:19
  • @jdehesa That is exactly what I needed! Awesome, thanks for the help. Don't you want to make it an answer? – schapke Mar 06 '20 at 13:34
  • @Liris I meant it to fill with any value besides 0. I actually need to fill them with specific values, but I can easily process any output with values other than 0 to get what I want. – schapke Mar 06 '20 at 13:37

1 Answers1

1

You can use scipy.ndimage.binary_fill_holes for that:

import scipy

a = np.array([
    [0, 0, 1, 1, 1],
    [0, 0, 1, 0, 1],
    [0, 0, 1, 1, 1],
    [0, 0, 0, 0, 0],
    [2, 2, 2, 0, 0],
    [2, 0, 2, 0, 0],
    [2, 2, 2, 0, 0],
])
b = scipy.ndimage.binary_fill_holes(a)
print(b.astype(int))
# [[0 0 1 1 1]
#  [0 0 1 1 1]
#  [0 0 1 1 1]
#  [0 0 0 0 0]
#  [1 1 1 0 0]
#  [1 1 1 0 0]
#  [1 1 1 0 0]]

One problem with this is it does not maintain the shape id. If you want that, it may be a bit more complicated... If you don't have cases where one shape is inside another one, maybe this can work:

import scipy

a = np.array([
    [0, 0, 1, 1, 1],
    [0, 0, 1, 0, 1],
    [0, 0, 1, 1, 1],
    [0, 0, 0, 0, 0],
    [2, 2, 2, 0, 0],
    [2, 0, 2, 0, 0],
    [2, 2, 2, 0, 0],
])
b = np.zeros_like(a)
for i in range(a.max()):
    shape = i + 1
    b += shape * scipy.ndimage.binary_fill_holes(a == shape)
print(b)
# [[0 0 1 1 1]
#  [0 0 1 1 1]
#  [0 0 1 1 1]
#  [0 0 0 0 0]
#  [2 2 2 0 0]
#  [2 2 2 0 0]
#  [2 2 2 0 0]]

There are still complicated cases. For example, the input:

1 1 1
1 0 2
2 2 2

Would produce all ones in the first snippet and no changes in the second one. Depending on what exactly you need you can tweak the code as necessary.

jdehesa
  • 58,456
  • 7
  • 77
  • 121