web-dev-qa-db-ja.com

numpyの大きな配列にルックアップテーブルを適用する便利な方法はありますか?

結果の配列にかなりの数のピクセルが含まれる画像が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コードを呼び出す便利な関数です。

26
Profpatsch

image1Dの場合、lutを使用して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から始まります。

39

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 lutを使用して画像をRGBから他の色空間に変換するときに、3Dルックアップを1D平坦化ルックアップに変換するロジックを追加すると、x10のスピードアップが可能になります。

16
Jaime