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

时间:2011-09-14 20:40:39

标签: python 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可以提高上述算法的效率吗?

3 个答案:

答案 0 :(得分:7)

您可以使用numpy.histogramdd执行此操作,但正如您所说,@ jozzas提出的方法将无效。您需要做的是展平三个3D阵列中的每一个,然后将它们组合成一个维度为(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位整数。

答案 1 :(得分:3)

假设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结果表明using_bincount比using_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

答案 2 :(得分:1)

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

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