以3x3D数组作为索引的numpy直方图



我有3x3D数组,它们是3D rgb图像的红色,绿色和蓝色通道。在numpy中创建输入通道的直方图体积的优雅方式是什么?

相当于

""" assume R, G and B are 3D arrays and output is a 3D array filled with zeros """
for x in x_dim:
     for y in y_dim:
          for z in z_dim:
               output[ R[x][y][z] ][ G[x][y][z] ][ B[x][y][z] ] += 1

这个代码对于大图像来说太慢了。numpy能否提高上述算法的效率?

您可以使用numpy.histogramdd,但是,正如您所说,@jozzas提出的方法不起作用。你要做的是把三个三维数组都压平然后把它们组合成一个二维数组(x_dim*y_dim*z_dim, 3),再传递给histogramdd。您的原始数据是3D的事实是一个转移注意力的问题,因为空间信息与计算直方图无关。

下面是在通道立方体中使用随机数据的示例:


import numpy 
n = 400  # approximate largest cube size that works on my laptop
# Fill channel cubes with random 8-bit integers
r = numpy.random.randint(256, size=(n,n,n)).astype(numpy.uint8)
g = numpy.random.randint(256, size=(n,n,n)).astype(numpy.uint8)
b = numpy.random.randint(256, size=(n,n,n)).astype(numpy.uint8)
# reorder data into for suitable for histogramming
data = numpy.vstack((r.flat, g.flat, b.flat)).astype(numpy.uint8).T
# Destroy originals to save space
del(r); del(g); del(b)
m = 256                                  # size of 3d histogram cube
hist, edges = numpy.histogramdd(
    data, bins=m, range=((-0.5,255.5),(-0.5,255.5),(-0.5,255.5))
    )
# Check that it worked
assert hist.sum() == n**3, 'Failed to conserve pixels'

这确实使用了比您预期更多的内存,因为histogramdd似乎使用64位浮点数来完成它的工作,即使我们向它发送8位整数。

假设8位通道,整数的3元组(R,G,B)可以被认为是一个以256为基数的数字:R*256**2 + G*256 + B。因此,我们可以将3个数组R,G,B转换为单个"颜色值"数组,并使用np.bincount生成所需的直方图。

import numpy as np
def using_bincount(r,g,b):
    r=r.ravel().astype('int32')
    g=g.ravel().astype('int32')
    b=b.ravel().astype('int32')
    output=np.zeros((base*base*base),dtype='int32')
    result=np.bincount(r*base**2+g*base+b)
    output[:len(result)]+=result
    output=output.reshape((base,base,base))
    return output
def using_histogramdd(r,g,b):
    data = np.vstack((r.flat, g.flat, b.flat)).astype(np.uint8).T
    del(r); del(g); del(b)
    hist, edges = np.histogramdd(
        data, bins=base, range=([0,base],[0,base],[0,base])
        )
    return hist
np.random.seed(0)
n = 200
base = 256
r = np.random.randint(base, size=(n,n,n)).astype(np.uint8)
g = np.random.randint(base, size=(n,n,n)).astype(np.uint8)
b = np.random.randint(base, size=(n,n,n)).astype(np.uint8)
if __name__=='__main__':
    bhist=using_bincount(r,g,b)
    hhist=using_histogramdd(r,g,b)
    assert np.allclose(bhist,hhist)

这些timeit结果表明,使用ing_bincount比使用ing_histogramdd更快,可能是因为histogramdd是为处理浮点数和作为范围的bin而构建的,而bincount仅用于计数整数。

% python -mtimeit -s'import test' 'test.using_bincount(test.r,test.g,test.b)'
10 loops, best of 3: 1.07 sec per loop
% python -mtimeit -s'import test' 'test.using_histogramdd(test.r,test.g,test.b)'
10 loops, best of 3: 8.42 sec per loop

您可以使用numpy的histogramdd来计算n维数组的直方图。如果您不想要每个2d切片的直方图,请确保将该维度的bins设置为1。

要获得整体直方图,您可以分别计算R, G和B通道,然后为每个位置取三个通道的最大值。

最新更新