1

私はApple の OpenGL Shader Builder (Nvidia の fx composer に似たツールですが、より単純なツール) を使用してこのチュートリアルに従っていました。

フィルターを簡単に適用できましたが、正しく機能したかどうかはわかりません (もしそうなら、どうすれば出力を改善できますか)。たとえば、ぼかしフィルター: OpenGL 自体がテクスチャに対して何らかの画像処理を行うため、元の画像よりも高い解像度で表示される場合、OpenGL によって既にぼかしられています。次に、ぼやけた部分は処理されていない部分よりも明るいです。これは意味がないと思います。これは、直接の近隣からピクセルを取得するだけだからです。これは、

float step_w = (1.0/width);

よくわかりません:ピクセルは浮動小数点値を使用してインデックス付けされていますか??

ぼやけた画像 http://img218.imageshack.us/img218/6468/blurzt.png

編集:使用した正確なコードを添付するのを忘れました:

フラグメントシェーダー

// Originally taken from: http://www.ozone3d.net/tutorials/image_filtering_p2.php#part_2

#define KERNEL_SIZE 9

float kernel[KERNEL_SIZE];

uniform sampler2D colorMap;
uniform float width;
uniform float height;

float step_w = (1.0/width);
float step_h = (1.0/height);

// float step_w = 20.0;
// float step_h = 20.0;

vec2 offset[KERNEL_SIZE];

void main(void)
{
   int i = 0;
   vec4 sum = vec4(0.0);

   offset[0] = vec2(-step_w, -step_h);  // south west
   offset[1] = vec2(0.0, -step_h);      // south
   offset[2] = vec2(step_w, -step_h);       // south east

   offset[3] = vec2(-step_w, 0.0);      // west
   offset[4] = vec2(0.0, 0.0);          // center
   offset[5] = vec2(step_w, 0.0);       // east

   offset[6] = vec2(-step_w, step_h);       // north west
   offset[7] = vec2(0.0, step_h);       // north
   offset[8] = vec2(step_w, step_h);        // north east


// Gaussian kernel
// 1 2 1
// 2 4 2
// 1 2 1


   kernel[0] = 1.0;     kernel[1] = 2.0;    kernel[2] = 1.0;
   kernel[3] = 2.0; kernel[4] = 4.0;    kernel[5] = 2.0;
   kernel[6] = 1.0;     kernel[7] = 2.0;    kernel[8] = 1.0;


// TODO make grayscale first
// Laplacian Filter
// 0   1   0
// 1  -4   1
// 0   1   0

/*
kernel[0] = 0.0;    kernel[1] = 1.0;    kernel[2] = 0.0;
kernel[3] = 1.0;    kernel[4] = -4.0;   kernel[5] = 1.0;
kernel[6] = 0.0;   kernel[7] = 2.0; kernel[8] = 0.0;
*/

// Mean Filter
// 1  1  1
// 1  1  1
// 1  1  1

/*
kernel[0] = 1.0;    kernel[1] = 1.0;    kernel[2] = 1.0;
kernel[3] = 1.0;    kernel[4] = 1.0;    kernel[5] = 1.0;
kernel[6] = 1.0;   kernel[7] = 1.0; kernel[8] = 1.0;
*/

   if(gl_TexCoord[0].s<0.5)
   {
       // For every pixel sample the neighbor pixels and sum up
       for( i=0; i<KERNEL_SIZE; i++ )
       {
            // select the pixel with the concerning offset
            vec4 tmp = texture2D(colorMap, gl_TexCoord[0].st + offset[i]);
            sum += tmp * kernel[i];
       }

        sum /= 16.0;
   }
   else if( gl_TexCoord[0].s>0.51 )
   {
        sum = texture2D(colorMap, gl_TexCoord[0].xy);
   }
   else // Draw a red line
   {
        sum = vec4(1.0, 0.0, 0.0, 1.0);
   }

   gl_FragColor = sum;
}

頂点シェーダー

void main(void)
{
    gl_TexCoord[0] = gl_MultiTexCoord0;
    gl_Position = ftransform();
}
4

2 に答える 2

4

テクスチャ座標は通常(0,0)(左下) から(1,1)(右上) に到達するため、実際には float です。

したがって、 texturecoordinates がある場合(u,v)、「元の」座標は によって計算され(u*textureWidth, v*textureHeight)ます。

結果の値が整数でない場合、それを処理する別の方法があるかもしれません:

  • 数を整数にするために、結果のfloorまたはを取るだけですceil
  • 隣接するテクセル間を補間する

ただし、すべてのシェーディング言語には、「元の」、つまり整数インデックスによってテクスチャにアクセスする方法があると思います。

于 2010-05-09T12:02:25.103 に答える
0

@ Nils、このコードを投稿していただきありがとうございます。私はしばらくの間、GPUで畳み込みを行う簡単な方法を見つけようとしてきました。私はあなたのコードを試してみて、同じ調光問題に自分で遭遇しました。これが私がそれを解決した方法です。

  • 画像の幅ではなくテクスチャの幅を使用するには、ステップサイズに注意する必要があります。テクスチャがopenglでバインドされると、通常は2の累乗にサイズ変更されます。
  • また、カーネル内のすべての値を合計し、それで割って、カーネルを正規化する必要があります。
  • また、照明なしでRGとBを別々に畳み込む場合にも役立ちます(サンプルの4番目のコンポーネント)。

これは、調光の問題がなく、3x3カーネルのオフセット配列の必要性を回避するソリューションです。

調光せずに機能する8つのカーネルを含めました。

uniform sampler2D colorMap;
uniform float width;
uniform float height;


const mat3 SobelVert= mat3( 1.0, 2.0, 1.0, 0.0, 0.0, 0.0, -1.0, -2.0, -1.0 );
const mat3 SobelHorz= mat3( 1.0, 0.0, -1.0, 2.0, 0.0, -2.0, 1.0, 0.0, -1.0 );
const mat3 SimpleBlur= (1.0/9.0)*mat3( 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 );
const mat3 Sharpen= mat3( 0.0, -1.0, 0.0, -1.0, 5.0, -1.0, 0.0, -1.0, 0.0 );
const mat3 GaussianBlur= (1.0/16.0)*mat3( 1.0, 2.0, 1.0, 2.0, 4.0, 2.0, 1.0, 2.0, 1.0 );
const mat3 SimpleHorzEdge= mat3( 0.0, 0.0, 0.0, -3.0, 3.0, 0.0, 0.0, 0.0, 0.0 );
const mat3 SimpleVertEdge= mat3( 0.0, -3.0, 0.0, 0.0, 3.0, 0.0, 0.0, 0.0, 0.0 );
const mat3 ClearNone= mat3( 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0 );

void main(void)
{
   vec4 sum = vec4(0.0);
   if(gl_TexCoord[0].x <0.5)
   {
      mat3 I, R, G, B;
      vec3 sample;

      // fetch the 3x3 neighbourhood and use the RGB vector's length as intensity value
      for (int i=0; i<3; i++){
        for (int j=0; j<3; j++) {
          sample = texture2D(colorMap, gl_TexCoord[0].xy + vec2(i-1,j-1)/vec2(width, height)).rgb;
          I[i][j] = length(sample); //intensity (or illumination)
          R[i][j] = sample.r; 
          G[i][j] = sample.g;
          B[i][j] = sample.b;  
        }
      }

      //apply the kernel convolution
      mat3 convolvedMatR = matrixCompMult( SimpleBlur, R);
      mat3 convolvedMatG = matrixCompMult( SimpleBlur, G);
      mat3 convolvedMatB = matrixCompMult( SimpleBlur, B);
      float convR = 0.0;
      float convG = 0.0;
      float convB = 0.0;
      //sum the result
      for (int i=0; i<3; i++){
        for (int j=0; j<3; j++) {
          convR += convolvedMatR[i][j];
          convG += convolvedMatG[i][j];
          convB += convolvedMatB[i][j];
        }
      }
      sum = vec4(vec3(convR, convG, convB), 1.0);

  }
   else if( gl_TexCoord[0].x >0.51 )
   {
        sum = texture2D(colorMap, gl_TexCoord[0].xy );
   }
   else // Draw a red line
   {
        sum = vec4(1.0, 0.0, 0.0, 1.0);
   }

   gl_FragColor = sum;
}
于 2011-12-23T07:19:53.877 に答える