具有周期性边界条件(包装)的numpy数组的边界框

时间:2019-12-11 16:01:44

标签: python arrays numpy bounding-box

我想做一些类似于this问题或this问题,但要使用周期性边界条件(包装)。我将举一个简单的例子。

假设我有以下numpy数组:

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 

然后,通过使用两个链接的问题中提出的方法之一,我能够提取非零值的边界框:

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

但是,如果非零元素“越过”边界并回到另一侧,就像这样:

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 

那么结果是:

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 

这不是我想要的。我希望结果与之前的情况相同。我正在尝试找出一种明智的方式来执行此操作,但是我被困住了。有人有主意吗?

1 个答案:

答案 0 :(得分:0)

我们可以像这样修改this答案:

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)))

运行:

[[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]]