0~255を取る値からヒートマップ(RGB)を算出するプログラムを作っていましたが、
最初に書いたソース(GPU+Cupy)が遅すぎたため、試行錯誤した結果を残します。
※cv2.applyColorMap(grayscale_image,cv2.COLORMAP_JET)で全て解決でしたが、自作してしまいました(恥)。
下記は、画像サイズ320x180に対する処理です。
コードは主要部分のみ載せています。
また、ヒートマップは近似値を求める簡易版(三角関数未使用)です
(値の大きさをサーモグラフィのような色に変換するの線形の図)。
GPU+Cupy(for)
元々書いていたコードです。
愚直にforで回して処理する負け組コードです。
def conv_v_to_heat(v):
image = cuda.cupy.zeros((v.shape[0], array.v[1], 4))
for i, w in enumerate(image):
for j, h in enumerate(w):
image[i,j,0] = get_heat_r(array[i][j])
image[i,j,1] = get_heat_g(array[i][j])
image[i,j,2] = get_heat_b(array[i][j])
image[i,j,3] = array[i][j] # アルファは適当
def get_heat_r(v):
if v <= 127:
return 0
elif v <= 190:
return (v-127)*4
else:
return 255
sec: 20.43495798110962
CPU+Numpy(for)
for使うくらいならGPUやめてしまったほうがまだましなのでは?
と思ってCPUに変えました(ソース省略)。
sec: 0.6369609832763672
CPUのほうが全然速かったです。
CPU+Numba+Numpy(for)
Numba入れてみました。
@jit
def conv_v_to_heat(v):
@jit
def get_heat_r(v):
sec: 0.20061397552490234
更に速くなりました。
CPU+Numba+Numpy(filter)
そもそも、Numpyにforを使う時点で負け組なので、
フィルタリングで対処するようにしました。
def conv_v_to_heat(v):
image = np.zeros((v.shape[0], v.shape[1], 4))
image[:, :, 0] = get_r(array)
image[:, :, 1] = get_g(array)
image[:, :, 2] = get_b(array)
image[:, :, 3] = v
def get_heat_r(v):
out = np.zeros((v.shape))
out[...] = 255
out[(v<=190)] = (v[(v<=190)]-127)*4
out[(v<=127)] = 0
return out
sec: 0.0013210773468017578
圧倒的に速くなりました。
CPU+Numpy(filter)
試しに、Numba外してみます。
sec: 0.001230478286743164
あれ、速くなりました。というか誤差レベルです。
GPU+Cupy(filter)
じゃあGPUは?
sec: 0.008527278900146484
遅くなりました。
まとめ
実装 | time(sec) |
---|---|
GPU+Cupy(for) | 20.43495798110962 |
CPU+Numpy(for) | 0.63696098327637 |
CPU+Numba+Numpy(for) | 0.20061397552490 |
CPU+Numba+Numpy(filter) | 0.00132107734680 |
CPU+Numpy(filter) | 0.00123047828674 |
GPU+Cupy(filter) | 0.00852727890015 |
CPU+Numpy(filter)が一番でした。
もっと速い実装はあると思いますが、個人的には満足行く速度になりました。
やっぱ、for使ったら負けすね。