1. 程式人生 > >演算法優化學習:(二)二維高斯濾波的引入

演算法優化學習:(二)二維高斯濾波的引入

1.高斯分佈

1.1一維高斯分佈

高斯分佈又稱為正態分佈,是一種廣泛應用的概率分佈,一維高斯分佈比較常見,相關數學定義如下所示。

對於不同的均值和標準差,一維高斯分佈曲線如下,可以看出標準差越大麴線越平坦,分佈越平均;標準差越小,曲線越陡峭,分佈越不均勻。

1.2二維高斯分佈

影象一般作為二維資料處理,相應的會用到二維高斯分佈。二維高斯分佈的數學定義和分佈曲線如下圖所示。

                   

二維高斯分佈有一個很重要的性質,即G(x,y) =G(x)*G(y) ,這一點在後面對二維高斯濾波的優化十分重要。

2.影象中的高斯濾波

由於種種原因,影象中總是存在噪聲,假若以灰度圖的形式描述影象,噪聲的灰度值與其鄰域灰度值往往差別較大(不過邊緣畫素點也有這個特徵),這就為去噪提供一種簡單的思路:既然噪聲灰度值相對“突出”,就利用鄰域的灰度資訊做平衡。因此常見的去噪演算法包括中值濾波(取某畫素鄰域的中間值作為該畫素的灰度值),均值濾波(對應畫素鄰域的平均值),還有高斯濾波。高斯濾波簡單來說利用了高斯分佈,直觀上看鄰域中距離畫素點距離越近的點其加權權值越高,反之越低。

對於二維高斯濾波,一個重要引數就是標準差,標準差對於高斯分佈的影響上面已經提到。以3X3大小的二維高斯濾波為例,對於某個畫素點,以其為中心的3X3鄰域如下圖所示,在x、y方向取值如下,將其帶入G(x,y)可得到高斯分佈對應的權值。不過這些權值的和不等於1(小於1),一般會把它們再做歸一化處理。

設高斯濾波半徑為r,則鄰域大小一般為2*r+1,生成高斯濾波加權係數示例程式碼如下。

void generateGaussianTemplate(double window[][11], int r, double sigma)
{
    static const double pi = 3.1415926;
    int center = r; // 模板的中心位置,也就是座標的原點
    int ksize = 2*r + 1;// 鄰域邊長
    double x2, y2;
    double sum = 0;
    for (int i = 0; i < ksize; i++)
    {
        x2 = pow(i - center, 2);
        for (int j = 0; j < ksize; j++)
        {
            y2 = pow(j - center, 2);
            double g = exp(-(x2 + y2) / (2 * sigma * sigma));
            g /= 2 * pi * sigma;
            sum += g;
            window[i][j] = g;
        }
    }
    
    for (int i = 0; i < ksize; i++)
    {
        for (int j = 0; j < ksize; j++)
        {
            window[i][j] /= sum;
        }
    }
}

之後就是使用該權值模板對畫素點鄰域做加權求和。對於M*N大小的灰度圖,若二維高斯濾波模板半徑為r,則完成濾波需要(2*r+1)*(2*r+1)*M*N次乘法和((2*r+1)*(2*r+1)-1)*M*N次加法。

3.二維高斯濾波的簡化

利用二維高斯濾波的數學性質可以減少演算法運算量,相關推導過程如下。

這樣做,從演算法層面降低了運算複雜度。

對於模板大小固定的高斯濾波,可1)提前計算好模板值儲存起來,免去每次需要重新計算模板值2)模板值與鄰域畫素的浮點乘法,轉換為定點乘法與除法,且儘量使用移位代替除法(會帶來一定的精度損失)

這樣就從演算法層面完成了一些優化,後面開始嘗試使用多執行緒和NEON指令集對程式碼進行優化