【问题标题】:Is there a convenient way to apply a lookup table to a large array in numpy?有没有一种方便的方法可以将查找表应用于 numpy 中的大型数组?
【发布时间】:2013-01-05 02:31:39
【问题描述】:

我已将一张图像读入 numpy,结果数组中有不少像素。

我计算了一个包含 256 个值的查找表。现在我想做以下事情:

for i in image.rows:
    for j in image.cols:
        mapped_image[i,j] = lut[image[i,j]]

是的,这基本上就是 lut 的作用。
唯一的问题是:我想做到高效,在 python 中调用该循环会让我等待几秒钟才能完成。

我知道numpy.vectorize(),它只是一个调用相同python代码的便捷函数。

【问题讨论】:

标签: arrays numpy python-2.x lookup-tables


【解决方案1】:

如果lut1D,您可以只使用image 来索引lut
这是 NumPy 中索引的入门:
http://www.scipy.org/Tentative_NumPy_Tutorial#head-864862d3f2bb4c32f04260fac61eb4ef34788c4c

In [54]: lut = np.arange(10) * 10

In [55]: img = np.random.randint(0,9,size=(3,3))

In [56]: lut
Out[56]: array([ 0, 10, 20, 30, 40, 50, 60, 70, 80, 90])

In [57]: img
Out[57]: 
array([[2, 2, 4],
       [1, 3, 0],
       [4, 3, 1]])

In [58]: lut[img]
Out[58]: 
array([[20, 20, 40],
       [10, 30,  0],
       [40, 30, 10]])

请注意索引从0开始

【讨论】:

  • face-desk 这太简单了,我可以尖叫。我一直在想另一个方向,但它行不通。但当然,numpy 是按元素来做的,所以这是显而易见的解决方案。也许我昨​​天太累了。 ;)
  • 实际上,它似乎也适用于多维 LUTS,至少对于 numpy 1.9.2
【解决方案2】:

TheodrosZelleke 的回答是正确的,但我只是想为它添加一些无证智慧。 Numpy 提供了一个函数np.take,根据文档“它与花式索引的作用相同。”

嗯,差不多,但不完全相同:

>>> import numpy as np
>>> lut = np.arange(256)
>>> image = np.random.randint(256, size=(5000, 5000))
>>> np.all(lut[image] == np.take(lut, image))
True
>>> import timeit
>>> timeit.timeit('lut[image]',
...               'from __main__ import lut, image', number=10)
4.369504285407089
>>> timeit.timeit('np.take(lut, image)',
...               'from __main__ import np, lut, image', number=10)
1.3678052776554637

np.take 大约快 3 倍!根据我的经验,当使用 3D luts 将图像从 RGB 转换为其他颜色空间时,添加将 3D 查找转换为 1D 扁平化查找的逻辑可以使速度提高 10 倍。

【讨论】:

  • 哦,哇,我深入研究了np.put 一段时间,因为我认为这可能会奏效。如果没有,我没有检查其他功能。 -.-
  • 这些时间已经过去两年了:从 1.9 开始的新版 NumPy 具有大大改进的精美索引机制,现在与使用 take 的速度相当。
  • 看来 lut[image] 现在 (NumPy 1.20) 比 np.take(lut, image) 快两倍以上。
【解决方案3】:

如果您仅限于使用 numpy,TheodrosZelleke's answer 是您的最佳选择。但是如果你允许其他模块,cv2 是一个与图像数据交互的有用模块,它接受 numpy 数组作为输入。一个很大的限制是图像数组必须有dtype='uint8',但只要没问题,函数cv2.LUT 就完全符合我们的要求,并且它提供了显着的加速:

>>> import numpy as np
>>> import cv2
>>> lut = np.arange(256, dtype='uint8')
>>> image = np.random.randint(256, size=(5000, 5000), dtype='uint8')
>>> np.all(lut[image] == cv2.LUT(image, lut))
True
>>> import timeit
>>> timeit.timeit('lut[image]', 'from __main__ import lut, image', number=10)
0.5747578000000431
>>> timeit.timeit('cv2.LUT(image, lut)', 
...               'from __main__ import cv2, lut, image', number=10)
0.07559149999997317

您的查找表可以是其他一些数据类型,但您会损失很多速度改进(尽管 numpy 索引也会影响性能)。例如,dtype='float64':

>>> lut = np.arange(256, dtype='float64')
>>> timeit.timeit('lut[image]', 'from __main__ import lut, image', number=10)
1.068468699999812
>>> timeit.timeit('cv2.LUT(image, lut)', 
...               'from __main__ import cv2, lut, image', number=10)
0.41085720000000947

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-18
    • 2018-02-04
    • 2011-08-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多