两幅图像重叠标签的计数 - Python / NumPy

3
我想用opencv解决以下问题。输入是两个png文件,每个像素的值在0到10之间。对于这11个值中的每一个,我想知道两个输入文件之间有多少个像素重叠。例如,假设img1.png的像素从(0,0)到(0,26)的值为3。img2.png的像素从(0,2)到(0,30)和(1,0)到(1,5)的值为3。因此,img1有27个值为3的像素。img2有35个值为3的像素。其中有25个重叠的像素,即从(0,2)到(0,26)的像素。
我想要一种快速提取这些信息的方法:0-10值之间有多少个像素重叠?每个图像有多少个值为0-10的像素?利用这些信息,我想制定每个值的重叠得分。
我知道,朴素地看,我可以逐个像素地查看每个图像,并使用累加器计算这些信息。但是这似乎会非常慢,而且opencv允许对图像使用numpy数组索引,所以我知道可能有一种加速这些计算的方法。然而,我不熟悉opencv或numpy,也不太确定如何进行操作。
目前正在参考这个链接:http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_core/py_basic_ops/py_basic_ops.html
1个回答

2

方法 #1 : 第一个方法包括以下步骤:

  • 获取两个数组(图像数组)之间的相等掩码。

  • 获取其中一个数组与标签范围之间的相等掩码。

  • 最后,在前两个步骤中获得的两个数组之间进行张量求和缩减,从而给出所有标签的计数。

因此,我们将使用 NumPy广播np.einsum 来实现一个矢量化方案,用于张量求和缩减,如下所示 -

def overlap_count(a, b, num_label):
    eq_mask = a==b
    id_mask = a == np.arange(num_label)[:,None, None]
    count = np.einsum('ij,aij->a',eq_mask, id_mask.astype(int))
    return count

样例运行 -

In [95]: a
Out[95]: 
array([[0, 1, 2, 1],
       [2, 0, 2, 2],
       [0, 1, 1, 0]])

In [96]: b
Out[96]: 
array([[0, 0, 1, 1],
       [1, 1, 1, 0],
       [1, 0, 1, 0]])

In [97]: overlap_count(a, b, num_label=3)
Out[97]: array([2, 2, 0])
方法二:我们可以利用np.bincount来提高第一种方法的内存效率和性能。其思想是,我们可以避免创建巨大的id_mask数组,而是对eq_mask的缩放版本进行计数。这个缩放版本将按照其中一个数组的值进行缩放。现在,这将为标记为0的像素进行更多的计数,因此我们需要单独计数。

因此,这种第二种方法会看起来像这样 -

def overlap_count_improved(a, b, num_label):
    eq_mask = a==b
    r = a * eq_mask
    count = np.bincount(r.ravel())
    count[0] = (eq_mask*(a == 0)).sum() 
    # or count[0] = np.einsum('ij,ij->', eq_mask, (a==0).astype(int))
    return count

我花了一些时间才理解你在这里做什么,但这确实是解决问题的一种非常聪明的方式。非常感谢你的帮助! - Terry Martin

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