Numpy:查找非零值的出现次数,按索引

时间:2016-03-19 20:01:29

标签: python numpy

我有一组3D数组,每个数组代表一个图像。我想找到给定坐标在所有数组中包含非黑色像素的出现次数。

result = np.zeros_like(list_of_arrays[0])
for array in list_of_arrays:
    for (y, x) in np.argwhere(array.any(-1)):
        result[y][x] += 1
return result

如何才能最好地改善这种天真的实施方式?如果我知道如何将第三维转换为0或1,我可以复制每个数组然后添加它们以获得我的答案。问题是我不知道如何进行转换。

两张3x3照片的示例

# picture 1
[[[ 208.,  208.,  208.],
  [   0.,    0.,    0.],
  [ 110.,  110.,  110.]],

 [[ 161.,  161.,  161.],
  [ 140.,  140.,  140.],
  [ 251.,  251.,  251.]],

 [[   0.,    0.,    0.],
  [  55.,   55.,   55.],
  [  26.,   26.,   26.]]]

# picture 2
[[[  88.,   88.,   88.],
  [ 140.,  140.,  140.],
  [   0.,    0.,    0.]],

 [[  18.,   18.,   18.],
  [ 112.,  112.,  112.],
  [   0.,    0.,    0.]],

 [[   0.,    0.,    0.],
  [ 195.,  195.,  195.],
  [   5.,    5.,    5.]]]

# what I'd like
[[[ 2.,  2.,  2.],
  [ 1.,  1.,  1.],
  [ 1.,  1.,  1.]],

 [[ 2.,  2.,  2.],
  [ 2.,  2.,  2.],
  [ 1.,  1.,  1.]],

 [[ 0.,  0.,  0.],
  [ 2.,  2.,  2.],
  [ 2.,  2.,  2.]]]

2 个答案:

答案 0 :(得分:2)

假设这两个图像是名为pic1pic2的numpy数组:

pic1 = np.array(
    [[[ 208.,  208.,  208.],
      [   0.,    0.,    0.],
      [ 110.,  110.,  110.]],

     [[ 161.,  161.,  161.],
      [ 140.,  140.,  140.],
      [ 251.,  251.,  251.]],

     [[   0.,    0.,    0.],
      [  55.,   55.,   55.],
      [  26.,   26.,   26.]]]
)

pic2 = np.array(
    [[[  88.,   88.,   88.],
      [ 140.,  140.,  140.],
      [   0.,    0.,    0.]],

     [[  18.,   18.,   18.],
      [ 112.,  112.,  112.],
      [   0.,    0.,    0.]],

     [[   0.,    0.,    0.],
      [ 195.,  195.,  195.],
      [   5.,    5.,    5.]]]
)

您可以使用np.array([pic1, pic2])创建这些图像的numpy数组,或者如果您已经将图像放在列表中np.array(list_of_arrays)。然后,对这个四维数组分别对每个元素应用逻辑运算,检查每个元素是否为非零。最后,对指定axis=0

的结果四维数组求和
# Get a numpy array of images
images = np.array([pic1, pic2]) # or np.array(list_of_arrays)

# Check for nonzero values and sum along the relevant axis
result = (images != 0).sum(axis=0)

array([[[2, 2, 2],
        [1, 1, 1],
        [1, 1, 1]],

       [[2, 2, 2],
        [2, 2, 2],
        [1, 1, 1]],

       [[0, 0, 0],
        [2, 2, 2],
        [2, 2, 2]]])

如果图像已经在列表中,那么这种方法可能没有其他方法那么快。也就是说,如果您在第一次创建图像集时可以选择数据结构,并且可以使用numpy数组,那么这是最快的。

答案 1 :(得分:1)

由于黑色由0表示,您可以使用array.astype('bool')将数组转换为布尔值,以便黑色变为False,其他每种颜色变为True。将这些数组与sum组合在一起会将它们转换回整数,而True会转换为1,这样您最终会得到每个坐标处的非黑色像素数:

result = sum(ar.astype('bool') for ar in list_of_arrays)

作为数据类型转换的替代方法,您可以使用numpy.minimum对图像进行阈值处理:

result = sum(np.minimum(ar, 1) for ar in list_of_arrays)

编辑:对于速度至关重要的情况,我已经进行了一项比较上述两种方法与ohruunuruus的基准比较:

>>> ar = [np.array([[ 208.,  208.,  208.],
       [   0.,    0.,    0.],
       [ 110.,  110.,  110.]]), np.array([[ 161.,  161.,  161.],
       [ 140.,  140.,  140.],
       [ 251.,  251.,  251.]]), np.array([[  0.,   0.,   0.],
       [ 55.,  55.,  55.],
       [ 26.,  26.,  26.]])]

>>> from time import time
>>> def f1(arrays):
...     return sum(np.minimum(a, 1) for a in arrays)
...
>>> def f2(arrays):
...     return sum(a.astype('bool') for a in arrays)
...
>>> def f3(arrays):
...     return (np.array(arrays) != 0).sum(axis=0)
...
>>> def timeIt(func):
...     start = time()
...     for i in range(1000000):
...         func(ar)
...     stop = time()
...     return stop-start
...

>>> timeIt(f1)
12.203268051147461
>>> timeIt(f2)
16.594016790390015
>>> timeIt(f3)
18.328339099884033

结果可能因图像的数量和大小不同而不同。