从3D numpy像素数组中删除空的“行”和“列”

时间:2016-01-11 20:45:37

标签: python arrays numpy

我基本上想要用numpy裁剪图像 - 我有一个3维numpy.ndarray对象,即:

[ [0,0,0,0], [255,255,255,255], ....]
  [0,0,0,0], [255,255,255,255], ....] ]

我要删除空格,在上下文中,它被称为[0,0,0,0]的整行或整列。

让每个像素只是这个例子的数字,我试图基本上这样做:

鉴于此:*编辑:选择一个稍微复杂的例子来澄清

[ [0,0,0,0,0,0] [0,0,1,1,1,0] [0,1,1,0,1,0] [0,0,0,1,1,0] [0,0,0,0,0,0]]

我正在努力创造这个:

[ [0,1,1,1], [1,1,0,1], [0,0,1,1] ]

我可以用循环来强制这个,但直觉上我觉得numpy有更好的方法来做到这一点。

3 个答案:

答案 0 :(得分:4)

一般情况下,您希望查看scipy.ndimage.labelscipy.ndimage.find_objects以提取符合条件的连续区域的边界框。

但是,在这种情况下,您可以使用" plain" numpy的。

我假设你在这里有一个nrows x ncols x nbands数组。 nbands x nrows x ncols的另一个约定也很常见,所以看一下数组的形状。

考虑到这一点,你可能会做类似的事情:

mask = im == 0
all_white = mask.sum(axis=2) == 0
rows = np.flatnonzero((~all_white).sum(axis=1))
cols = np.flatnonzero((~all_white).sum(axis=0))

crop = im[rows.min():rows.max()+1, cols.min():cols.max()+1, :]

对于您的2D示例,它看起来像:

import numpy as np

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

mask = im == 0
rows = np.flatnonzero((~mask).sum(axis=1))
cols = np.flatnonzero((~mask).sum(axis=0))

crop = im[rows.min():rows.max()+1, cols.min():cols.max()+1]
print crop

让我们稍微分解2D示例。

In [1]: import numpy as np

In [2]: im = np.array([[0,0,0,0,0,0],
   ...:                [0,0,1,1,1,0],
   ...:                [0,1,1,0,1,0],
   ...:                [0,0,0,1,1,0],
   ...:                [0,0,0,0,0,0]])

好的,现在让我们创建一个符合我们条件的布尔数组:

In [3]: mask = im == 0

In [4]: mask
Out[4]:
array([[ True,  True,  True,  True,  True,  True],
       [ True,  True, False, False, False,  True],
       [ True, False, False,  True, False,  True],
       [ True,  True,  True, False, False,  True],
       [ True,  True,  True,  True,  True,  True]], dtype=bool)

另请注意,~运算符在布尔数组上的作用为logical_not

In [5]: ~mask
Out[5]:
array([[False, False, False, False, False, False],
       [False, False,  True,  True,  True, False],
       [False,  True,  True, False,  True, False],
       [False, False, False,  True,  True, False],
       [False, False, False, False, False, False]], dtype=bool)

考虑到这一点,要找到所有元素都为false的行,我们可以对列进行求和:

In [6]: (~mask).sum(axis=1)
Out[6]: array([0, 3, 3, 2, 0])

如果没有元素为True,我们将得到0。

类似于查找所有元素都为false的列,我们可以对各行求和:

In [7]: (~mask).sum(axis=0)
Out[7]: array([0, 1, 2, 2, 3, 0])

现在我们需要做的就是找到第一个和最后一个不为零的。在这种情况下,np.flatnonzerononzero容易一些:

In [8]: np.flatnonzero((~mask).sum(axis=1))
Out[8]: array([1, 2, 3])

In [9]: np.flatnonzero((~mask).sum(axis=0))
Out[9]: array([1, 2, 3, 4])

然后,您可以根据最小/最大非零元素轻松切出区域:

In [10]: rows = np.flatnonzero((~mask).sum(axis=1))

In [11]: cols = np.flatnonzero((~mask).sum(axis=0))

In [12]: im[rows.min():rows.max()+1, cols.min():cols.max()+1]
Out[12]:
array([[0, 1, 1, 1],
       [1, 1, 0, 1],
       [0, 0, 1, 1]])

答案 1 :(得分:0)

您可以使用np.nonzero函数查找零值,然后从原始数组中切割非零元素并重塑为您想要的值:

import numpy as np
n = np.array([ [0,0,0,0,0,0],
   [0,0,1,1,1,0],
   [0,0,1,1,1,0],
   [0,0,1,1,1,0],
   [0,0,0,0,0,0]])

elems = n[n.nonzero()]

In [415]: elems
Out[415]: array([1, 1, 1, 1, 1, 1, 1, 1, 1])

In [416]: elems.reshape(3,3)
Out[416]: 
array([[1, 1, 1],
       [1, 1, 1],
       [1, 1, 1]])

答案 2 :(得分:0)

为任意尺寸实现此功能的一种方法是:

import numpy as np

def trim(arr, mask):
    bounding_box = tuple(
        slice(np.min(indexes), np.max(indexes) + 1)
        for indexes in np.where(mask))
    return arr[bounding_box]

FlyingCircus免责声明:我是软件包的主要作者)中提供了一种稍微更灵活的解决方案(您可以在其中指示要作用于哪个轴)。