NumPy数组的阈值像素索引

时间:2016-02-09 20:11:31

标签: python arrays numpy vectorization

我确定这个问题是Googleable,但我不知道要使用哪些关键字。我对一个特定的案例感到好奇,但也对如何做到这一点感到好奇。假设我有一个RGB图像作为形状(width, height, 3)的数组,我想找到红色通道大于100的所有像素。我觉得image > [100, 0, 0]应该给我一个索引数组(如果我正在比较标量和使用灰度图像,但是这会将每个元素与列表进行比较。我如何比较每个"元素"的前两个维度?是最后一个维度?

1 个答案:

答案 0 :(得分:2)

要仅检测红色通道,您可以执行以下操作 -

np.argwhere(image[:,:,0] > threshold)

说明:

  1. red-channelthreshold进行比较,为我们提供一个与没有第三轴(颜色通道)的输入图像形状相同的布尔数组。
  2. 使用np.argwhere获取成功匹配的索引。
  3. 如果您想查看是否有任何通道高于某个阈值,请使用.any(-1)(任何满足最后一个轴/颜色通道条件的元素)。

    np.argwhere((image > threshold).any(-1))
    

    示例运行

    输入图片:

    In [76]: image
    Out[76]: 
    array([[[118,  94, 109],
            [ 36, 122,   6],
            [ 85,  91,  58],
            [ 30,   2,  23]],
    
           [[ 32,  47,  50],
            [  1, 105, 141],
            [ 91, 120,  58],
            [129, 127, 111]]], dtype=uint8)
    
    In [77]: threshold
    Out[77]: 100
    

    案例#1:仅限红色通道

    In [69]: np.argwhere(image[:,:,0] > threshold)
    Out[69]: 
    array([[0, 0],
           [1, 3]])
    
    In [70]: image[0,0]
    Out[70]: array([118,  94, 109], dtype=uint8)
    
    In [71]: image[1,3]
    Out[71]: array([129, 127, 111], dtype=uint8)
    

    案例#2:任意频道

    In [72]: np.argwhere((image > threshold).any(-1))
    Out[72]: 
    array([[0, 0],
           [0, 1],
           [1, 1],
           [1, 2],
           [1, 3]])
    
    In [73]: image[0,1]
    Out[73]: array([ 36, 122,   6], dtype=uint8)
    
    In [74]: image[1,1]
    Out[74]: array([  1, 105, 141], dtype=uint8)
    
    In [75]: image[1,2]
    Out[75]: array([ 91, 120,  58], dtype=uint8)
    

    np.any

    np.einsum的更快替代方案

    np.einsum可能会被欺骗以执行np.any的工作,因为事实证明它有点快。

    因此, boolean_arr.any(-1) 等同于 np.einsum('ijk->ij',boolean_arr)

    以下是各种数据集的相关运行时 -

    In [105]: image = np.random.randint(0,255,(30,30,3)).astype('uint8')
         ...: %timeit np.argwhere((image > threshold).any(-1))
         ...: %timeit np.argwhere(np.einsum('ijk->ij',image>threshold))
         ...: out1 = np.argwhere((image > threshold).any(-1))
         ...: out2 = np.argwhere(np.einsum('ijk->ij',image>threshold))
         ...: print np.allclose(out1,out2)
         ...: 
    10000 loops, best of 3: 79.2 µs per loop
    10000 loops, best of 3: 56.5 µs per loop
    True
    
    In [106]: image = np.random.randint(0,255,(300,300,3)).astype('uint8')
         ...: %timeit np.argwhere((image > threshold).any(-1))
         ...: %timeit np.argwhere(np.einsum('ijk->ij',image>threshold))
         ...: out1 = np.argwhere((image > threshold).any(-1))
         ...: out2 = np.argwhere(np.einsum('ijk->ij',image>threshold))
         ...: print np.allclose(out1,out2)
         ...: 
    100 loops, best of 3: 5.47 ms per loop
    100 loops, best of 3: 3.69 ms per loop
    True
    
    In [107]: image = np.random.randint(0,255,(3000,3000,3)).astype('uint8')
         ...: %timeit np.argwhere((image > threshold).any(-1))
         ...: %timeit np.argwhere(np.einsum('ijk->ij',image>threshold))
         ...: out1 = np.argwhere((image > threshold).any(-1))
         ...: out2 = np.argwhere(np.einsum('ijk->ij',image>threshold))
         ...: print np.allclose(out1,out2)
         ...: 
    1 loops, best of 3: 833 ms per loop
    1 loops, best of 3: 640 ms per loop
    True