使用NumPy填充形状/轮廓

4

我希望能够填写满足特定属性的numpy矩阵(可能使用掩码)。换句话说,它是某个形状的矩阵表示,例如,正方形可能为:

square =   [0,0,0,0,0;
            0,1,1,1,0;
            0,1,0,1,0;
            0,1,1,1,0]

成为:

s_filled = [0,0,0,0,0;
            0,1,1,1,0;
            0,1,1,1,0;
            0,1,1,1,0]

和圆形:
circle =   [0,0,0,0,0,0;
            0,0,1,1,0,0;
            0,1,0,0,1,0;
            0,0,1,1,0,0]

并变成:

c_filled = [0,0,0,0,0,0;
            0,0,1,1,0,0;
            0,1,1,1,1,0;
            0,0,1,1,0,0]

使用仅限numpy,没有其他外部库,是否可以实现此功能/算法?我想将此函数/算法应用于300x300的形状。

非常感谢!


发布的解决方案对您有用吗? - Divakar
谢谢你的回答,但不好意思,我需要更通用的解决方案。这只适用于在内部形状中填充1,而外部则全部为0(反之则不行)。 - Rebecca Ash
2个回答

5
使用np.maximum.accumulate非常简单,我们可以先沿着行从左到右使用它,然后再从右到左使用,通过减法来获取非零的公共区域。对于凸形状,这将非常有效。
因此,具体实现如下 -
def fill_contours(arr):
    return np.maximum.accumulate(arr,1) & \
           np.maximum.accumulate(arr[:,::-1],1)[:,::-1]

这是对任意形状的示例运行 -
In [176]: arbitrary
Out[176]: 
array([[0, 0, 1, 0, 0, 0, 0],
       [0, 1, 0, 1, 0, 0, 0],
       [1, 0, 0, 0, 1, 0, 0],
       [0, 1, 0, 0, 1, 0, 0],
       [0, 1, 0, 0, 1, 0, 0],
       [0, 0, 1, 0, 0, 1, 0],
       [0, 1, 0, 0, 1, 0, 0],
       [0, 1, 1, 1, 0, 0, 0]])

In [177]: fill_contours(arbitrary)
Out[177]: 
array([[0, 0, 1, 0, 0, 0, 0],
       [0, 1, 1, 1, 0, 0, 0],
       [1, 1, 1, 1, 1, 0, 0],
       [0, 1, 1, 1, 1, 0, 0],
       [0, 1, 1, 1, 1, 0, 0],
       [0, 0, 1, 1, 1, 1, 0],
       [0, 1, 1, 1, 1, 0, 0],
       [0, 1, 1, 1, 0, 0, 0]])

当我填充圆形对象时,这个解决方案对我非常有效。我认为它很普适。 - Chris Farr

2
这是对@Divakar的答案进行微调以解决某些边缘情况下填充凹面的小修补。
原始解决方案无法解决此问题,因为它没有跳过垂直轴上的元素。
例如:
# check out index (7, 2), the result should be 0.0

a = np.array([[0, 0, 1, 0, 0, 0, 0],
              [0, 1, 0, 1, 0, 0, 0],
              [1, 0, 0, 0, 1, 0, 0],
              [0, 1, 0, 0, 1, 0, 0],
              [0, 1, 0, 0, 1, 0, 0],
              [0, 0, 1, 0, 0, 1, 0],
              [0, 0, 1, 0, 1, 0, 0],
              [0, 1, 0, 1, 0, 0, 0]])

fill_contours(a)
"""
original_result
 0.0  0.0  1.0  0.0  0.0  0.0  0.0 
 0.0  1.0  1.0  1.0  0.0  0.0  0.0 
 1.0  1.0  1.0  1.0  1.0  0.0  0.0 
 0.0  1.0  1.0  1.0  1.0  0.0  0.0 
 0.0  1.0  1.0  1.0  1.0  0.0  0.0 
 0.0  0.0  1.0  1.0  1.0  1.0  0.0 
 0.0  0.0  1.0  1.0  1.0  0.0  0.0 
 0.0  1.0  1.0  1.0  0.0  0.0  0.0 
"""

# not apply the fix by considering vertical axis
def fill_contours_fixed(arr):
    return np.maximum.accumulate(arr, 1) &\
           np.maximum.accumulate(arr[:, ::-1], 1)[:, ::-1] &\
           np.maximum.accumulate(arr[::-1, :], 0)[::-1, :] &\
           np.maximum.accumulate(arr, 0)

fill_contours_fixed(a)

"""
fixed_result, (7, 2) is now correct
 0.0  0.0  1.0  0.0  0.0  0.0  0.0 
 0.0  1.0  1.0  1.0  0.0  0.0  0.0 
 1.0  1.0  1.0  1.0  1.0  0.0  0.0 
 0.0  1.0  1.0  1.0  1.0  0.0  0.0 
 0.0  1.0  1.0  1.0  1.0  0.0  0.0 
 0.0  0.0  1.0  1.0  1.0  1.0  0.0 
 0.0  0.0  1.0  1.0  1.0  0.0  0.0 
 0.0  1.0  0.0  1.0  0.0  0.0  0.0  
"""

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接