スポンサーサイト

--年--月--日 --:--

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

GL で畳み込み処理

2009年01月15日 00:02

シェーダーを使わずに gl でカーネルによる畳み込み

画像をぼかしたり、エッジの抽出にガウスやラプラシアン、LoG や DoG なんていうカーネルを使い畳み込みをかけたい場合があります。
実は GL にはこういう画像の積分計算用のフィルタ処理関数があります。

これは 1.2 から入った機能ですので、前回と同様、やっぱり wglGetProcAddress や glew で関数を使用できる状態にしなければいけません。


まず手順から(2次元の畳み込み処理の場合)

 1:glEnable( GL_CONVOLUTION_2D ) で畳み込み処理を有効にする
 2:glConvolutionFilter2D でカーネルを指定する。
 3:glBegin ~ glEnd で描画を行う


なんてことはないですね、結果に対して処理するだけなので。
Stencil Test などと処理手順は変わりません。
出来上がった画像はフィルタが通されたものになります。


さて、使用する関数なのですが、、、


void glConvolutionFilter2D(GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* image);

2次元の指定したカーネルによる畳み込み処理を行います。
target には GL_CONVOLUTION_2D のみ指定可能です。
internalformat には畳み込み処理を行いたいピクセル成分を定義します。
glColorTable などで指定できるカラーフォーマットを指定してください。
width と height にはカーネルの大きさを入れてください。3 x 3 のカーネルを使用するなら、width = 3, height = 3 になります。
グラフィックボードのドライバがどこまでサポートしているのか?は glGetConvolutionParameter 関数を使って問い合わせます(後述)
format と type には image に格納されたカーネルフィルタのカラーフォーマットを定義します。
例えば、image に輝度値のテーブルを浮動小数点で指定する場合は、format に GL_LUMINANCE、type には GL_FLOAT を渡します。





です。
なかなかに複雑な関数。。

glConvolutionFilter2D で指定する internalformat と format は同じでなくてもかまいません。
format に GL_ALPHA を指定した場合は alpha 成分のみに作用しますし、GL_RGB を指定した場合は、R, G, B それぞれに作用します。
簡単なテーブルにして見ましょう。

カーネルのフォーマット R G B A
GL_ALPHA Rs Gs Bs As * Af
GL_LUMINANCE Rs * Lf Gs * Lf Bs * Lf As
GL_LUMINANCE_ALPHA Rs * Lf Gs * Lf Bs * Lf As * La
GL_INTENSITY Rs * If Gs * If Bs * If As * Ia
GL_RGB Rs * Rf Gs * Gf Bs * Bf As
GL_ALPHA Rs * Rf Gs * Gf Bs * Bf As * Af

 
Rs、Gs、Bs、As はソースの各成分で Rf、Gf、Bf、Af、Lf、La、If はカーネルの各成分になります。
internalformat が LUMINANCE 系、INTENSITY の場合は Rs だけに影響があると考えてください。


さて、2次元のカーネルは1次元のカーネルの外積として表現することで分離可能です。
この場合、2次元の場合は 3 x 3 の場合は 9 回の畳み込みが必要ですが、1次元に分離したカーネルの場合は 3 + 3 で 6 回の畳み込みで ok です。
要するに高速化できるわけです。


そんなわけで、このような分離可能フィルタを使用する関数もあります。


void glSeparableFilter2D(GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* row, const void* column)

2次元の分離可能な畳み込みフィルタを定義します。
target には GL_SEPARABLE_2D だけが指定可能です。
internalformat、format、type については glConvolutionFilter2D と同じです。
width には row に渡される要素数を height には column に渡される要素数を指定します。
row には x 軸方向の 1 次元カーネルを、height には y 軸方向の 1 次元カーネルを指定します。





もっとも、最近の GPU だと何回もラスタライズする方が重いので、どこまで高速化するかはわかりませんが。。。
CPU でやるなら、分離したほうが格段に早くなります。



画像の縁の畳み込み処理は、縁ではない場所の畳み込み処理と若干違う処理を適応したい場合があります。
このような要望にこたえるため、畳み込み境界モードというのがあります。

使用する関数は glConvolutionParameter 関数です。


void glConvolutionParameterf(GLenum target, GLenum pname, GLfloat param)
void glConvolutionParameterfv(GLenum target, GLenum pname, const GLfloat* param)
void glConvolutionParameteri(GLenum target, GLenum pname, GLint param)
void glConvolutionParameteriv(GLenum target, GLenum pname, const GLint* param)

target には GL_CONVOLUTION_2D、GL_CONVOLUTION_1D、GL_SEPARABLE_2D が使用可能です。
pname には GL_CONVOLUTION_BORDER_MODE、GL_CONVOLUTION_BORDER_COLOR、GL_CONVOLUTION_FILTER_SCALE、GL_CONVOLUTION_FILTER_BIAS が指定可能です。
GL_CONVOLUTION_BORDER_MODE の場合は境界での畳み込み処理の方法を指定できます。
param には GL_REDUCE、GL_CONSTANT_BORDER、GL_REPLICATE_BORDER が指定可能です。

GL_REDUCE の場合は、出来上がった画像はカーネルの大きさだけ小さくなります。
3 x 3 のカーネルを使用した場合、出来上がった画像は元の画像より横幅と縦幅を 3 だけ小さくした画像が出来上がります。

GL_CONSTANT_BORDER の場合は、縁の外側は GL_CONVOLUTION_BORDER_COLOR で指定した色データと見て処理します。

GL_REPLICATE_BORDER の場合は、縁の外側は最も外側にあるピクセルと同じ色が続くと見て処理されます。

GL_CONVOLUTION_BORDER_COLOR は GL_CONSTANT_BORDER で使用する縁の外側の色を指定します。 param には RGBA からなる4つの値を指定できます。

GL_CONVOLUTION_BORDER_COLOR は GL_CONSTANT_BORDER で使用する縁の外側の色を指定します。 param には RGBA からなる4つの値を指定できます。

GL_CONVOLUTION_FILTER_SCALE は畳み込み処理が入る前に積算する値を指定できます。

GL_CONVOLUTION_FILTER_BIAS は畳み込み処理が入る前に加算する値、終わった後に減算する値を指定できます。
(要するに、128 を指定すると、128 を 0 と見なして畳み込みすることが出来る)







先ほど、実際に使用できるカーネルの横幅と縦幅を指定する関数として glGetConvolutionParameter 関数を上げました。
この関数の使用方法も載せておきます。

void glGetConvolutionParameteriv(GLenum target, GLenum pname, GLfloat* params)
void glGetConvolutionParameterfv(GLenum target, GLenum pname, GLfloat* params)

target には GL_CONVOLUTION_2D、GL_CONVOLUTION_1D、GL_SEPARABLE_2D が指定できます。
pname と params に格納される値は多いので、箇条書きで書きます。

GL_CONVOLUTION_BORDER_COLOR ・・・畳み込みの演算で使用される境界色(浮動小数点数)
GL_CONVOLUTION_MODE ・・・畳み込みの境界処理方法。glConvolutionParameter 関数の説明を参照(整数)
GL_CONVOLUTION_FILTER_SCALE ・・・畳み込み演算処理時に使用される積算値(浮動小数点数)
GL_CONVOLUTION_FILTER_BIAS ・・・畳み込み演算処理時に使用されるバイアス値(浮動小数点数)
GL_CONVOLUTION_FORMAT ・・・渡されたカーネルのフォーマット(整数)
GL_CONVOLUTION_WIDTH ・・・カーネルの横方向の最大幅(整数)
GL_CONVOLUTION_HEIGHT ・・・カーネルの縦方向の最大幅(整数)







さて、こんな畳み込み演算ですが、シェーダーを使う分には別に要りません(・∀・)
シェーダーで任意の処理を掛けるわけですから、必要なわけないですよね。

もしかしたら、ハードウェア実装されて高速化されるのかもしれませんが、、、。
誰か試したら教えてください。
スポンサーサイト


コメント

    コメントの投稿

    (コメント編集・削除に必要)
    (管理者にだけ表示を許可する)

    トラックバック

    この記事のトラックバックURL
    http://angra.blog31.fc2.com/tb.php/131-e4b9c90d
    この記事へのトラックバック


    最近の記事


    上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。