1. 程式人生 > >影象基本變換---影象快速高斯模糊演算法

影象基本變換---影象快速高斯模糊演算法

本文將詳細介紹經典高斯濾波的相關內容。

高斯濾波器實質上是一種訊號的濾波器,其用途是訊號的平滑處理。它是一類根據高斯函式的形狀來選擇權重的線性平滑濾波器,該濾波器對於抑制服從正態分佈的噪聲非常有效。高斯函式的公式如下所示:

一維高斯函式:

               

二維高斯函式:

                         

對於二維高斯函式,它的分佈如下圖所示:

Fig.1二維Gauss分佈

對於二維高斯函式,我們設定兩個引數:高斯半徑r和方差sigma,由半徑r我們可以得到一個(2r+1)*(2r+1)大小的高斯核模板,計算函式程式碼如下(其中k是高斯模板的權係數,即歸一化係數):

private static double[,] GaussFuc(int rdouble sigma)

        {

            int size = 2 * r + 1;

            double[,] gaussResult = new double[sizesize];

            double k = 0.0;

            for (int y = -rh = 0; y <= ry++, h++)

            {

                for (int x = -rw = 0; x <= r

x++, w++)

                {

                    gaussResult[wh] = (1.0 / (2.0 * Math.PI * sigma * sigma)) * (Math.Exp(-((double)x * (double)x + (double)y * (double)y) / (2.0 * sigma * sigma)));

k += gaussResult[wh];

                }

            }

            return gaussResult;

        }

我們設定引數r=1,sigma=1.0,則得到一個3*3的高斯模板如下:

                      Fig.2 3*3高斯模板

通常,我們在影象處理中使用的高斯函式定義如下:

使用該公式得到3*3高斯模板如下:

Fig.3 3*3高斯模板

對模板修正,即可得到我們常用的3*3經典模板:

 Fig.4經典3*3高斯模板

   這就是經典高斯模板的計算過程,半徑不同,我們可以得到不同的模板。通常使用了3*3和5*5的經典模板:

Fig.5 Gauss 模板

   得到高斯模板後,我們用它對影象進行卷積,就可以得到高斯濾波的結果影象了。

   由於直接使用公式2-(97),計算量巨大,影響影象處理的,因此,我們採用快速演算法,即將公式2-(97)分解為如下公式:

這個公式可以理解為先對影象按行進行一次一維高斯濾波,在對結果影象按列進行一次一維高斯濾波,這樣速度將大大提高。

一維高斯濾波程式碼如下(包含歸一化):

  1. private static double[] GaussKernel1D(int r, double sigma)  
  2.         {  
  3.             double[] filter = new double[2 * r + 1];  
  4.             double sum = 0.0;  
  5.             for (int i = 0; i < filter.Length; i++)  
  6.             {  
  7.                 filter[i] = Math.Exp((double)(-(i - r) * (i - r)) / (2.0 * sigma * sigma));  
  8.                 sum += filter[i];  
  9.             }  
  10.             for (int i = 0; i < filter.Length; i++)  
  11.             {  
  12.                 filter[i] = filter[i] / sum;  
  13.             }  
  14.             return filter;  
  15.         } 
  1. private static double[] GaussKernel(int radius, double sigma)  
  2. {  
  3.     int length=2*radius+1;  
  4.     double[] kernel = new double[length];  
  5.     double sum = 0.0;  
  6.     for (int i = 0; i < length; i++)  
  7.     {  
  8.         kernel[i] = Math.Exp((double)(-(i - radius) * (i - radius)) / (2.0 * sigma * sigma));  
  9.         sum += kernel[i];  
  10.     }  
  11.     for (int i = 0; i < length; i++)  
  12.     {  
  13.         kernel[i] = kernel[i] / sum;  
  14.     }  
  15.     return kernel;  
  16. }  
  17. ///   
  18. /// Gauss filter process  
  19. ///   
  20. /// The source image.  
  21. /// The radius of gauss kernel,from 0 to 100.  
  22. /// The convince of gauss kernel, from 0 to 30.  
  23. ///   
  24. public static WriteableBitmap GaussFilter(WriteableBitmap src,int radius,double sigma) ////高斯濾波  
  25. {  
  26.     if (src != null)  
  27.     {  
  28.         int w = src.PixelWidth;  
  29.         int h = src.PixelHeight;  
  30.         WriteableBitmap srcImage = new WriteableBitmap(w, h);  
  31.         byte[] srcValue = src.PixelBuffer.ToArray();  
  32.         byte[] tempValue=(byte[])srcValue.Clone();  
  33.         double[] kernel = GaussKernel(radius, sigma);  
  34.         double tempB = 0.0, tempG = 0.0, tempR = 0.0;  
  35.         int rem = 0;  
  36.         int t = 0;  
  37.         int v = 0;  
  38.         double K = 0.0;  
  39.         for (int y = 0; y < h; y++)  
  40.         {  
  41.             for (int x = 0; x < w; x++)  
  42.             {  
  43.                 tempB = tempG = tempR = 0.0;  
  44.                 for (int k = -radius; k <= radius; k++)  
  45.                 {  
  46.                     rem = (Math.Abs(x + k) % w);  
  47.                     t = rem * 4 + y * w * 4;  
  48.                     K=kernel[k+radius];  
  49.                     tempB += srcValue[t] * K;  
  50.                     tempG += srcValue[t + 1] * K;  
  51.                     tempR += srcValue[t + 2] * K;  
  52.                 }  
  53.                 v = x * 4 + y * w * 4;  
  54.                 tempValue[v] = (byte)tempB;  
  55.                 tempValue[v + 1] = (byte)tempG;  
  56.                 tempValue[v + 2] = (byte)tempR;  
  57.             }  
  58.         }  
  59.         for (int x = 0; x < w; x++)  
  60.         {  
  61.             for (int y = 0; y < h; y++)  
  62.             {  
  63.                 tempB = tempG = tempR = 0.0;  
  64.                 for (int k = -radius; k <= radius; k++)  
  65.                 {  
  66.                     rem = (Math.Abs(y + k) % h);  
  67.                     t = rem * w * 4 + x * 4;  
  68.                     K = kernel[k + radius];  
  69.                     tempB += tempValue[t] * K;  
  70.                     tempG += tempValue[t + 1] * K;  
  71.                     tempR += tempValue[t + 2] * K;  
  72.                 }  
  73.                 v = x * 4 + y * w * 4;  
  74.                 srcValue[v] = (byte)tempB;  
  75.                 srcValue[v + 1] = (byte)tempG;  
  76.                 srcValue[v + 2] = (byte)tempR;  
  77.             }  
  78.         }  
  79.         Stream sTemp = srcImage.PixelBuffer.AsStream();  
  80.         sTemp.Seek(0, SeekOrigin.Begin);  
  81.         sTemp.Write(srcValue, 0, w * 4 * h);  
  82.         return srcImage;  
  83.     }  
  84.     else  
  85.     {  
  86.         return null;  
  87.     }  
  88. }