1. 程式人生 > >【Shader特效8】著色器濾鏡、影象卷積與濾波、數字影象處理

【Shader特效8】著色器濾鏡、影象卷積與濾波、數字影象處理

##說在開頭: PhotoShop和特效相機中有許多特效的濾鏡。片元著色器時基於片元為單位執行的,完全可以實現特殊的濾鏡效果。要想實現這些濾鏡效果還需要簡單的瞭解《數字影象處理》中的影象卷積與濾波的一些知識,我把所有程式碼都放到了我的github上https://github.com/ModestBean/ShaderSample。本人的知識有限,如果本節內容有錯誤和不合理之處,還請朋友們多多指出,我會虛心接受每一個建議。 #####參考內容:

  • 《OpenGL ES 3.X 遊戲開發 下卷》
  • zouxy09的部落格:http://blog.csdn.net/zouxy09/article/details/49080029
    我將兩者的精華內容進行了結合,同時結合了我自己的一些知識和著色器的相關知識。 ##影象卷積的原理 zouxy09的部落格中的內容很詳細,已下為他的部落格中的內容 這裡寫圖片描述 大家主要看三部分,源畫素值,卷積核心的值,最終的畫素值,看如何進行乘積的。(圖片右上角有計算過程) ####濾波器的規則要求: 1)濾波器的大小應該是奇數,這樣它才有一箇中心,例如3x3,5x5或者7x7。有中心了,也有了半徑的稱呼,例如5x5大小的核的半徑就是2。 2)濾波器矩陣所有的元素之和應該要等於1,這是為了保證濾波前後影象的亮度保持不變。當然了,這不是硬性要求了。 3)如果濾波器矩陣所有元素之和大於1,那麼濾波後的影象就會比原影象更亮,反之,如果小於1,那麼得到的影象就會變暗。如果和為0,影象不會變黑,但也會非常暗。 4)對於濾波後的結構,可能會出現負數或者大於255的數值。對這種情況,我們將他們直接截斷到0和255之間即可。對於負數,也可以取絕對值。 ##執行效果及程式碼 然後看看使用不同的卷積核心對圖片的影響吧。 ###平滑過濾 這裡寫圖片描述
    #####片元著色器程式碼(SmoothFilter.frag)
#version 400
#extension GL_ARB_separate_shader_objects : enable
#extension GL_ARB_shading_language_420pack : enable
layout (binding = 1) uniform sampler2D sTexture;//紋理取樣器
layout (location = 0) in vec2 vTextureCoord;//紋理座標
layout (location = 0) out vec4 outColor;//輸出片元顏色
void main() {
    //紋理偏移量單位步進
    const float stStep = 512.0;
    const float scaleFactor = 1.0/9.0;//給出最終求和時的加權因子(為調整亮度)
     //給出卷積核心中各個元素對應畫素相對於待處理畫素的紋理座標偏移量
    vec2 offsets[9]=vec2[9](
          vec2(-1.0,-1.0),vec2(0.0,-1.0),vec2(1.0,-1.0),
          vec2(-1.0,0.0),vec2(0.0,0.0),vec2(1.0,0.0),
          vec2(-1.0,1.0),vec2(0.0,1.0),vec2(1.0,1.0)
    );
    //卷積核心中各個位置的值
         float kernelValues[9]=float[9] (
                1.0,1.0,1.0,
                1.0,1.0,1.0,
                1.0,1.0,1.0
         );
     //最終的顏色值
     vec4 sum=vec4(0,0,0,0);
     //顏色求和
     for(int i=0;i<9;i++){
        sum=sum+kernelValues[i]*scaleFactor*texture(sTexture, vTextureCoord+offsets[i]/stStep);
     }
     outColor=sum;
}

顏色求和部分的程式碼稍微不好理解。 1、首先kernelValues[i]*scaleFactor,scaleFactor為卷積核心中數的和的倒數,也就是1/9,這麼做的目的是為了保持圖片的亮度與原來的亮度不變,這個數大於1時,處理後的圖片變亮,小於1處理後的圖片變暗。 2、然後是texture(sTexture, vTextureCoord+offsets[i]/stStep),這裡讓紋理座標的偏移量除以stStep,stStep為紋理座標偏移量的步進,在著色器中控制著濾波器處理區域的大小。 ###邊緣檢測 這裡寫圖片描述 #####片元著色器程式碼(EdgeDetection.frag)只給出卷積核心的值

//卷積核心中各個位置的值
      float kernelValues[9]=float[9] (
                  0.0,1.0,0.0,
                  1.0,-4.0,1.0,
                  0.0,1.0,0.0
           );

###銳化效果 這裡寫圖片描述 #####片元著色器程式碼(Sharpen.frag)只給出卷積核心的值

 float kernelValues[9]=float[9] (
                 0.0,-1.0,0.0,
                 -1.0,5.0,-1.0,
                 0.0,-1.0,0.0
          );

###浮雕效果 這裡寫圖片描述 #####片元著色器程式碼(SmoothFilter.frag)只給出卷積核心的值

  float kernelValues[9]=float[9] (
                 2.0,0.0,2.0,
                 0.0,0.0,0.0,
                 3.0,0.0,-6.0
          );

###均值模糊 這裡寫圖片描述 #####片元著色器程式碼(MeanBlur.frag)只給出卷積核心的值 可以多次模糊也是可以的

float kernelValues[9]=float[9] (
            0.0,1.0,0.0,
            1.0,1.0,1.0,
            0.0,1.0,0.0
     );

###高斯模糊 這裡寫圖片描述 #####片元著色器程式碼(GaussianBlur.frag)只給出卷積核心的值

 const float scaleFactor = 1.0/209.0;//給出最終求和時的加權因子(為調整亮度)
    //卷積核心中各個位置的值
     float kernelValues[9]=float[9] (
            16.0,26.0,16.0,
            26.0,41.0,26.0,
            16.0,26.0,16.0
     );

這裡的加權因子應該為卷積核心所有值的和的倒數。也就是1/209。 ##數字影象處理中卷積邊界的處理 他的部落格中總結的很好。 這裡寫圖片描述 這裡寫圖片描述 ##片元著色器中的邊界處理 對於片元著色器中的邊界處理我還沒有理解清楚,希望清楚的人可以解答。 ##最後 這裡只是簡單的介紹了幾種卷積核心,還有更多的卷積核心,不同的卷積核心實現的效果也不同,我只是把這些知識使用片元著色器實現了,有什麼問題可以互相討論,我的知識水平也有限,有什麼問題希望大家指出。