Share via


ピクセルシェーダー⑤ Sobel フィルター

image

今回からはピクセルシェーダーの実装例を紹介します。Sobel フィルターは輪郭抽出によく使われる畳み込みフィルターで、近傍のピクセルをサンプリングして、各ピクセルにカーネルと呼ばれる重みを乗算して加算します。

現在のピクセルの座標は uv 引数([0,1]で正規化)で渡されます。近傍のピクセルの位置を得るには画像のサイズが必要ですが、PsPad v1.0 には画像サイズを渡す定数レジスターが定義されていないので(v2.0で実装します!)、640 x 480 として位置を割り出しました。

float dx = 1.0/640.0;
float dy = 1.0/480.0;

中心のピクセルは使わないので、1ピクセルの生成に8回のサンプリングが必要です。PS_2.0でも16サンプラーがサポートされているので問題ありません。輝度値だけが欲しいので、Luminance 関数を作成します。

float luminance(float4 color)
{
return color.r*0.3 + color.g*0.59 + color.b*0.11;
}

UpLeft

Up

UpRight

Left

 

Right

DownLeft

Down

DownRight

float UpLeft = luminance(tex2D( implicitInputSampler,
float2(uv.x - dx, uv.y - dy)));
float Up = luminance(tex2D( implicitInputSampler,
float2(uv.x, uv.y - dy)));
float UpRight = luminance(tex2D( implicitInputSampler,
float2(uv.x + dx, uv.y - dy)));
float Left = luminance(tex2D( implicitInputSampler,
float2(uv.x - dx, uv.y - dy)));
float Right = luminance(tex2D( implicitInputSampler,
float2(uv.x + dx, uv.y - dy)));
float DownLeft = luminance(tex2D( implicitInputSampler,
float2(uv.x - dx, uv.y + dy)));
float Down = luminance(tex2D( implicitInputSampler,
float2(uv.x, uv.y+dy)));
float DownRight = luminance(tex2D( implicitInputSampler,
float2(uv.x + dx, uv.y + dy)));

以下のカーネルを使ってX方向とY方向の値を算出します。最終的なピクセル値はその二乗平均になります。

-1

0

1

-2

0

2

-1

0

1

X方向のカーネル

-1

-2

-1

0

0

0

1

2

1

Y方向のカーネル

float dX = -UpLeft - 2.0*Left - DownLeft + UpRight + 2.0*Right + DownRight;
float dY = -UpLeft - 2.0*Up - UpRight + DownLeft + 2.0*Down + DownRight;
float4 sobel = sqrt(dX*dX + dY*dY);
sobel.w = 1.0;

この畳み込みフィルターカーネルによる手法は、ぼかし(blur)など様々な画像処理に適用できます。

この Soble フィルター シェーダーは後ほど CodePlex の PsPad ページにアップロードします。