影をぼかす用途で、ブラー処理について延々と調べたのでまとめ。
長々とはてな日記を書いている最中にプレビューに失敗して内容が消えてしまった…。さすがHTMLのフォーム+JavaScript…。

GaussianBlur

Photoshopにあるガウスぼかし。滑らかにぼける。

StackBlur

http://incubator.quasimondo.com/processing/fast_blur_deluxe.php
ぼかしの半径を広げても速度が落ちにくい。

Exponential Blur

http://zrusin.blogspot.com/2006/07/more-blurring.html
StackBlurより品質は劣るけどもっと速いらしい。

BoxBlur

http://www.blackpawn.com/texts/blur/default.html
http://web.archive.org/web/20060718054020/http://www.acm.uiuc.edu/siggraph/workshops/wjarosz_convolution_2001.pdf

  • ガウスぼかし等と同様に縦と横を別々に処理してまず速度を上げられる。
  • ボックスフィルターの係数は全部同じなので、毎回範囲内のピクセルを全て集める必要は無くて、初回に集めた後は出るピクセルと入るピクセルの分を更新すれば済む。こうすればぼかしの半径を上げても殆ど処理に掛かる時間が上がらなくなる。

自分で実装

BoxBlur処理を1週間くらい掛けて色々と実装してみた。
http://www.geocities.jp/beruponu/code/boxblur_test.zip
Core2 Duo P9600で、2048*2048*8bit画像に対して半径16のぼかし処理を3回実行した場合の結果。x64での実行結果。x86だともっと差が開く。

実行時間(ms) 処理方法
13635.02205 馬鹿正直に全てのピクセル毎に縦横集めて畳み込み。
4303.47167 ポインタ利用。画素毎に範囲チェックしないようにする。
915.36040 横と縦を別々に処理。
782.50700 固定小数点演算使用。
9.63174 横処理。計算結果再利用。下とあわせて利用。
346.34765 縦処理。計算結果再利用。
9.12574 2つ上と同じ。横処理で計算結果再利用。下とあわせて利用。
11.59617 縦処理。計算結果再利用。順々にメモリにアクセス。
7.30386 横処理で計算結果再利用。SSEで最適化。下とあわせて利用。
4.34085 縦処理で計算結果再利用。SSEで最適化。
19.76571 横と縦をまとめて処理1。細かく処理。
22.38085 横と縦をまとめて処理2。大雑把に処理。
10.08341 横と縦をまとめて処理2をSSEで最適化。

低レベルな領域での最適化を頑張ればそれだけ効果が出るかと思ったら、腕が未熟で思ったほど速度が上がらなかった…。とりあえずもっとコアが欲しい。

今後

今後GPUがCPUに統合されていくみたいだけれど、単純な処理はGPUみたいに単純なコアをたくさん並べて処理した方が当然高速に実行出来るっぽい。IntelLarrabeeは最新のGPUに比べると処理能力が見劣りするらしくキャンセルされてしまったみたいだし。なので将来的に16コアのCPUが登場してAVXを使えるようになったとしても今の4コアでSSEより最大で8倍くらいしか性能が上がらないだろうから、GPUが生きる分野はありそう。…でも2コアのSSEより16倍速いのなら結構十分かも?QWUXGAの画像に対して何段もフィルタを重ねたのを60fpsとかは厳しいかも。

OpenCLで書いたらコンパイラがうまくターゲットに合わせて最適化してくれたらかなり楽なんだろうけれど、しっかりと色々な石向けに整備されるのはきっと遠い将来の事だろう…。