0

I would like to do something similar to this question, or this other one, but using periodic boundary conditions (wrapping). I'll make a quick example.

Let's say I have the following numpy array:

0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 1 1 1 1 1 0 
0 0 0 0 0 1 0 0 0 0 0 
0 0 0 0 0 1 0 0 0 0 0 
0 0 1 1 1 1 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 

Then, by using one of the methods proposed in the two linked questions, I am able to extract the bounding box of non-zero values:

0 0 0 1 1 1 1 1 
0 0 0 1 0 0 0 0 
0 0 0 1 0 0 0 0 
1 1 1 1 0 0 0 0

However, if the non-zero elements "cross" the border and come back on the other side, like so:

0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 
1 1 0 0 0 0 0 0 1 1 1 
0 0 0 0 0 0 0 0 1 0 0 
0 0 0 0 0 0 0 0 1 0 0 
0 0 0 0 0 1 1 1 1 0 0 
0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 

Then the result is:

1 1 0 0 0 0 0 0 1 1 1 
0 0 0 0 0 0 0 0 1 0 0 
0 0 0 0 0 0 0 0 1 0 0 
0 0 0 0 0 1 1 1 1 0 0 

which is not what I want. I would like the result to be the same as the previous case. I am trying to figure out an intelligent way to do this, but I am stuck. Anybody have ideas?

Tropilio
  • 1,395
  • 1
  • 9
  • 27

1 Answers1

0

We can adapt this answer like so:

import numpy as np

def wrapped_bbox(a):
    dims = [*range(1,a.ndim)]
    bb = np.empty((a.ndim,2),int)
    i = 0
    while True:
        n = a.shape[i]
        r = np.arange(1,2*n+1)
        ai = np.any(a,axis=tuple(dims))
        r1_a = np.where(ai,r.reshape(2,n),0).ravel()
        aux = np.maximum.accumulate(r1_a)
        aux = r-aux
        idx = aux.argmax()
        mx = aux[idx]
        if mx > n:
            bb[i] = 0,n
        else:
            bb[i] = idx+1, idx+1 - mx
            if bb[i,0] >= n:
                bb[i,0] -= n
            elif bb[i,1] == 0:
                bb[i,1] = n
        if i == len(dims):
            return bb
        dims[i] -= 1
        i += 1

# example
x = """
......
.x...-
..x...
.....x
"""

x = np.array(x.strip().split())[:,None].view("U1")
x = (x == 'x').view('u1')

print(x)
for r in range(x.shape[1]):
    print(wrapped_bbox(np.roll(x,r,axis=1)))

Run:

[[0 0 0 0 0 0]   # x
 [0 1 0 0 0 0]
 [0 0 1 0 0 0]
 [0 0 0 0 0 1]]
[[1 4]           # bbox vert
 [5 3]]          # bbox horz, note wraparound (left > right)
[[1 4]
 [0 4]]          # roll by 1
[[1 4]
 [1 5]]          # roll by 2
[[1 4]
 [2 6]]          # etc.
[[1 4]
 [3 1]]
[[1 4]
 [4 2]]
Paul Panzer
  • 51,835
  • 3
  • 54
  • 99