2012-03-08 22 views
4

私はこれを行う必要がなければホイールを再作成したくないでしょう。 OpenGL ESを使用したSobelフィルタの実装はありますか?OpenGL ESを使用したC/C++のSobelフィルタ

+0

あなたはこのリンクを見たことがありますか?ソーベルフィルタの例(http://royger.org/opencl/?p=22)しかし、これはOpenCLにあります。 – yasouser

答えて

15

Objective-Cが受け入れ可能な場合、私のGPUImageフレームワークとそのGPUImageSobelEdgeDetectionFilterを見ることができます。これは、OpenGL ES 2.0フラグメントシェーダを使用したSobelエッジ検出に適用されます。 this answerの "スケッチ"の例で、これからの出力を見ることができます。

Objective-Cコードを掘り下げたくない場合、ここでの重要な作業は2組のシェーダで実行されます。最初のパスでは、イメージを輝度に縮小し、その値を赤、緑、青の各チャンネルに保存します。

attribute vec4 position; 
attribute vec4 inputTextureCoordinate; 

varying vec2 textureCoordinate; 

void main() 
{ 
    gl_Position = position; 
    textureCoordinate = inputTextureCoordinate.xy; 
} 

とフラグメントシェーダ:私はこの次の頂点シェーダ用いないその後

precision highp float; 

varying vec2 textureCoordinate; 

uniform sampler2D inputImageTexture; 

const highp vec3 W = vec3(0.2125, 0.7154, 0.0721); 

void main() 
{ 
    float luminance = dot(texture2D(inputImageTexture, textureCoordinate).rgb, W); 

    gl_FragColor = vec4(vec3(luminance), 1.0); 
} 

を、私は実際にこの頂点を用いて(より明るいピクセルが、この場合のエッジである)のSobelエッジ検出を行いますシェーダ:

attribute vec4 position; 
attribute vec4 inputTextureCoordinate; 

uniform highp float imageWidthFactor; 
uniform highp float imageHeightFactor; 

varying vec2 textureCoordinate; 
varying vec2 leftTextureCoordinate; 
varying vec2 rightTextureCoordinate; 

varying vec2 topTextureCoordinate; 
varying vec2 topLeftTextureCoordinate; 
varying vec2 topRightTextureCoordinate; 

varying vec2 bottomTextureCoordinate; 
varying vec2 bottomLeftTextureCoordinate; 
varying vec2 bottomRightTextureCoordinate; 

void main() 
{ 
    gl_Position = position; 

    vec2 widthStep = vec2(imageWidthFactor, 0.0); 
    vec2 heightStep = vec2(0.0, imageHeightFactor); 
    vec2 widthHeightStep = vec2(imageWidthFactor, imageHeightFactor); 
    vec2 widthNegativeHeightStep = vec2(imageWidthFactor, -imageHeightFactor); 

    textureCoordinate = inputTextureCoordinate.xy; 
    leftTextureCoordinate = inputTextureCoordinate.xy - widthStep; 
    rightTextureCoordinate = inputTextureCoordinate.xy + widthStep; 

    topTextureCoordinate = inputTextureCoordinate.xy + heightStep; 
    topLeftTextureCoordinate = inputTextureCoordinate.xy - widthNegativeHeightStep; 
    topRightTextureCoordinate = inputTextureCoordinate.xy + widthHeightStep; 

    bottomTextureCoordinate = inputTextureCoordinate.xy - heightStep; 
    bottomLeftTextureCoordinate = inputTextureCoordinate.xy - widthHeightStep; 
    bottomRightTextureCoordinate = inputTextureCoordinate.xy + widthNegativeHeightStep; 
} 

と、このフラグメントシェーダ:

precision highp float; 

varying vec2 textureCoordinate; 
varying vec2 leftTextureCoordinate; 
varying vec2 rightTextureCoordinate; 

varying vec2 topTextureCoordinate; 
varying vec2 topLeftTextureCoordinate; 
varying vec2 topRightTextureCoordinate; 

varying vec2 bottomTextureCoordinate; 
varying vec2 bottomLeftTextureCoordinate; 
varying vec2 bottomRightTextureCoordinate; 

uniform sampler2D inputImageTexture; 

void main() 
{ 
    float i00 = texture2D(inputImageTexture, textureCoordinate).r; 
    float im1m1 = texture2D(inputImageTexture, bottomLeftTextureCoordinate).r; 
    float ip1p1 = texture2D(inputImageTexture, topRightTextureCoordinate).r; 
    float im1p1 = texture2D(inputImageTexture, topLeftTextureCoordinate).r; 
    float ip1m1 = texture2D(inputImageTexture, bottomRightTextureCoordinate).r; 
    float im10 = texture2D(inputImageTexture, leftTextureCoordinate).r; 
    float ip10 = texture2D(inputImageTexture, rightTextureCoordinate).r; 
    float i0m1 = texture2D(inputImageTexture, bottomTextureCoordinate).r; 
    float i0p1 = texture2D(inputImageTexture, topTextureCoordinate).r; 
    float h = -im1p1 - 2.0 * i0p1 - ip1p1 + im1m1 + 2.0 * i0m1 + ip1m1; 
    float v = -im1m1 - 2.0 * im10 - im1p1 + ip1m1 + 2.0 * ip10 + ip1p1; 

    float mag = length(vec2(h, v)); 

    gl_FragColor = vec4(vec3(mag), 1.0); 
} 

imageWidthFactorimageHeightFactorは入力イメージサイズの逆数です。

この2パスのアプローチは、上記のリンクされた答えより複雑です。これは、モバイルGPU(少なくともiOSデバイスのPowerVRバラエティのもの)で実行すると、元の実装が最も効率的ではなかったからです。すべての依存テクスチャ読み取りを削除し、輝度を事前計算して最終シェーダの赤チャンネルからサンプリングするだけで、この調整されたエッジ検出方法は、1回のパスですべてのことを行う純粋な方法よりもベンチマークで20倍高速です。

関連する問題