エッジフィルター


~リアルタイム写真屋~




■はじめに

今回は、レンダリングした後の画像の輪郭をとるエッジフィルターです。
このエフェクトは、DOUBLE-S.T.E.A.Lで有名になりましたが、 私の知り合いは、DOUBLE-S.T.E.A.Lの広告を見て、「リアルタイムフォトショップだね」といっていました。
まぁ、だからどうしたという感じですが、実装してみました。

まぁ、いつものように適当にファイルが入っています。

final.vsh頂点シェーダー。
final.pshピクセルシェーダー。
draw.cppメインの描画部分。
draw.h描画の各関数の定義。
bg.cpp背景の描画。
main.h基本的な定数など。
main.cpp描画に関係しないシステム的な部分。
load.cppロード。
load.hロードのインターフェイス。
tile.bmp (床デカール)
sky.bmp (空デカール)

あと、実行ファイル及び、プロジェクトファイルが入っています。

■加工手順

どのような加工をしているか順を追って説明しましょう。

先ずは、元画像です。 テクスチャーにレンダリングして、画像を作り上げます。

隣のピクセルの「輝度」の差でエッジを抽出します。
輝度を

輝度 = 0.299f*赤 + 0.587f*緑 + 0.114f*青

で、計算します。

次に、近くのピクセルとの輝度の差を取って、エッジを抽出します。
輝度の差をとるポイントは、対角的にとります。
中心から、前後、左右に0.5離れた4点で、対角的に差をとります。

差をとったピクセルですが、本当は、

差の大きさ = |ピクセルの差1|+|ピクセルの差2|

と、絶対値でとらないと、差をとった符号によって、一部が消えてしまいます。
ただし、絶対値の計算は大変なので、近似的に符号を消すための演算である絶対値の2乗

差の大きさ = (ピクセルの差1)2+(ピクセルの差2)2

をとって、近似します。

あっ、上の絵は、色のスケーリングをして、強弱を強めています。
さて、輪郭にするために、ネガポジ変換して、輪郭を抽出します。

これを、元の画像と合成(乗算)をすれば、今回の画像が求まります。

以上で、出来上がりです。

■ピクセルシェーダー

さて、どのようにして、以上の手続きを実現するか、ピクセルシェーダーのプログラムを見てみましょう。

0001: ; final.psh
0002: ;      (c) 2002 IMAGIRE Takashi
0003: 
0004: ps.1.0
0005: 
0006: def c0, 0.299f, 0.587f, 0.114f, 0.0f    ; 輝度の重み
0007: 
0008: tex t0      ; 0:1 0  1:0 1  2:0 0  3:0 0
0009: tex t1      ;   0 0    0 0    1 0    0 1
0010: tex t2
0011: tex t3
0012: 
0013: dp3 r0,      t0, c0         ;         rgb        a
0014: dp3 r0.rgb,  t1, c0         ; r0 = (t0の輝度、t1の輝度)
0015: dp3 r1,      t3, c0         ; r1 = (t3の輝度、t2の輝度)
0016: dp3 r1.rgb,  t2, c0
0017: 
0018: add_x4     r0,   r0,-r1     ; r0 =  4( t3-t0の輝度,     t2-t1の輝度)
0019: mul_x4     r0,   r0, r0     ; r0 = 64((t3-t0の輝度)^2, (t2-t1の輝度)^2)
0020: add_x4_sat r0, 1-r0,-r0.a   ; r0 = 4*(1-64((t2-t0の輝度)^2+(t3-t1の輝度)^2))
0021: mul_sat    r0, r0,   t1     ; 求めたエッジに色を乗せる

テクスチャー座標は、あらかじめずらしておきます(頂点シェーダーで被写界深度をやった時と同じ方法です)。
そのテクスチャーをロードた後、内積命令を使って輝度を求めます。
テンポラリレジスタは2つしかないので、アルファ成分と色成分にそれぞれ違うピクセルの輝度を格納します。
次に、足し算命令を使って、引き算して、エッジをしらべます。また、強弱を強調するために、結果を4倍します。
次に、掛け算命令をして、2乗します。これで、負の値が消えます。
その後、足し算をして、(ネガポジ反転しつつ)輝度を合成します。これで、輪郭が得られました。
最後に、色をかけて出来上がりです。

■最後に

シェーダ部分しか説明しませんでしたが、それ以外は今までにやってきたことなので、すぐわかると思います。
このフィルター自体は、そんなに綺麗でもないので、使いどころは微妙ですが、 エッジを検出できるということは、いろいろな計算ができるので、使いどころは満載でしょう。




もどる

imagire@gmail.com