Blender で numpy を使う
カテゴリ:blender
基本的な使い方はnumpyの使い方やBlenderではじめる画像処理を参照。
高速化に関してはNumPyによる数値計算の高速化 : 基礎やNumPyから最高のパフォーマンスを得る方法が参考になる。
データの型を指定する
データの型を指定せずに numpy.array で配列に変換すると、型は float64 になる。
import bpy import numpy as np img = bpy.data.images['image'] arr = np.array(img.pixels[:]) print(arr.dtype) #arr は dtype('float64')
float64 は計算が遅い。たいていの場合 float32 で十分精度は足りる。テクスチャなら float16 でも十分だ。その方がメモリ使用量が少ないうえ計算も速い。型の指定は dtype でできる。
arr = np.array(img.pixels[:], dtype=np.float16)
ベンチマーク
以下のコードは画像の R 成分を 0 にする処理のベンチマークだ。
import bpy import numpy as np import time def timer_alloc(img, dtype): oldtime = time.time() arr = np.array(img.pixels[:], dtype=dtype) if dtype==np.float16: str_type='float16' elif dtype==np.float32: str_type='float32' else: str_type='float64' print("alloc time %s : %08f sec" % (str_type, time.time()-oldtime)) return arr def timer_process(arr, text): oldtime = time.time() arr[0::4] = 0.0 # R成分に一括で0を代入 print("process time %s: %08f sec\n" % (text, time.time()-oldtime)) img = bpy.data.images['big_texture'] #float 16 arr = timer_alloc(img, np.float16) timer_process(arr, 'float16') # float 32 arr = timer_alloc(img, np.float32) timer_process(arr, 'float32') # float 64 arr = timer_alloc(img, np.float64) timer_process(arr, 'float64')
結果は以下のようになった。

ベンチ結果
このベンチではメモリの型に関わらず、メモリコピーにかかる時間は同じだった。float16 と float32 とを比べると約4倍ほど float16 の方が速い。
numpy.array が遅いのはメモリコピーの部分だ。メモリ確保の速度は numpy.empty() を使えば高速だ。しかし numpy でない配列アクセスが遅いので、メモリコピーの部分は高速化できない。
整数を使う
整数で十分な精度なら int8 を使うことでさらに高速になる。float から int への変換コストがかかるが、処理が複雑ならやる価値はある。
# 上のベンチの最後に追加する # float16 to int8 oldtime = time.time() arr = arr * 255 arr = arr.astype(np.int8) print("alloc time %s : %08f sec" % ('int8', time.time()-oldtime)) timer_process(arr, 'int8')

ベンチ結果
int8 の処理時間は float16 の処理時間の半分になっている。float64 と比べると8倍速い。