・カーネル内のループは時間が掛かる
フィルタ処理を行う場合、CUDAカーネル内で、フィルタ係数を二重ループで走査する。
このとき、フィルタサイズが大きいと、許容できないほどの処理時間を要してしまう。
例えば、1920x1080の画像に65x65の線形フィルタ(もしくはerodeフィルタ)を適用
したときの処理時間は、約150ミリ秒であった。
・高速フーリエ変換を積極的に活用すべき
そこで、線形フィルタを、周波数空間で適用するようにしたら、処理時間が約150ミリ秒から
約4ミリ秒に改善した。なお、高速フーリエ変換は、1920x1080の画像で約1.5ミリ秒だった。
また、周波数空間における画素ごとの乗算は約1ミリ秒だった。
すなわち、フィルタサイズがいくら大きくても、計算時間は一定である。
知っている人には当たり前かもしれないが、高速フーリエ変換を使わない手はない。
・関係無い画素はスキップすべき
また、erodeフィルタなど、フィルタ係数が1になっている領域の最大値(や最小値)を
求める処理では、フィルタ係数が0になっている領域を走査しないようにした。具体的には、
フィルタ係数が1になっている場所の座標を配列に格納し、CUDAカーネル内では、
配列に格納されている座標の画素だけを走査するようにした。その結果、処理時間が
約1ミリ秒に改善した。(※ただし、フィルタ係数は非常にスパースで、99%以上が0)
なお、上記方法で実装したコードについては以下の記事で紹介
https://qiita.com/rueiwoqpqpwoeiru/items/69a931e4042a4f9d4434
(追記)
二値画像に対するモルフォロジー処理は、高速フーリエ変換を用いることで高速化できる。
dilateの場合、fftによる畳み込みを行い、閾値処理で二値化する。
erodeの場合、0-1を反転してから、fftによる畳み込みを行い、
閾値処理で二値化した後、0-1を反転する。