opencv 高斯模糊

高斯模糊是一種圖像模糊濾波器,它用正態分佈計算圖像中每一個像素的變換。N 維空間正態分佈方程爲php

G(r) = \frac{1}{\sqrt{2\pi \sigma^2}^N} e^{-r^2/(2 \sigma^2)}

在二維空間定義爲html

G(u,v) = \frac{1}{2\pi \sigma^2} e^{-(u^2 + v^2)/(2 \sigma^2)}

其中 r 是模糊半徑 (r2 = u2 + v2),σ 是正態分佈的標準誤差。在二維空間中,這個公式生成的曲面的等高線是從中心開始呈正態分佈的同心圓。分佈不爲零的像素組成的卷積矩陣與原始圖像作變換。每一個像素的值都是周圍相鄰像素值的加權平均。原始像素的值有最大的高斯分佈值,因此有最大的權重,相鄰像素隨着距離原始像素愈來愈遠,其權重也愈來愈小。這樣進行模糊處理比其它的均衡模糊濾波器更高地保留了邊緣效果,參見尺度空間實現es6

理論上來說,圖像中每點的分佈都不爲零,這也就是說每一個像素的計算都須要包含整幅圖像。在實際應用中,在計算高斯函數的離散近似時,在大概3σ距離以外的像素均可以看做不起做用,這些像素的計算也就能夠忽略。一般,圖像處理程序只須要計算  (6 \sigma + 1) \times (6 \sigma + 1)  的矩陣就能夠保證相關像素影響。數據結構

除了圓形對稱以外,高斯模糊也能夠在二維圖像上對兩個獨立的一維空間分別進行計算,這叫做線性可分。這也就是說,使用二維矩陣變換獲得的效果也能夠經過在水平方向進行一維高斯矩陣變換加上豎直方向的一維高斯矩陣變換獲得。從計算的角度來看,這是一項有用的特性,由於這樣只須要 O(n \times M \times N) + O(m \times M \times N) 次計算,而不可分的矩陣則須要 O(m \times n \times M \times N) 次計算,其中 M,N 是須要進行濾波的圖像的維數,mn 是濾波器的維數。函數

對一幅圖像進行屢次連續高斯模糊的效果與一次更大的高斯模糊能夠產生一樣的效果,大的高斯模糊的半徑是所用多個高斯模糊半徑平方和的平方根。例如,使用半徑分別爲 6 和 8 的兩次高斯模糊變換獲得的效果等同於一次半徑爲 10 的高斯模糊效果,\sqrt{6\times6 + 8\times8} = 10。根據這個關係,使用多個連續較小的高斯模糊處理不會比單個高斯較大處理時間要少。spa

在減少圖像尺寸的場合常常使用高斯模糊。在進行欠採樣的時候,一般在採樣以前對圖像進行低通濾波處理。這樣就能夠保證在採樣圖像中不會出現虛假的高頻信息。高斯模糊有很好的特性,如沒有明顯的邊界,這樣就不會在濾波圖像中造成震盪。code

原文地址htm

 

實際應用中圖像數據的類型多是unsigned char ,float ,double ,所以我用自定義模板數據結構:blog

template<typename T>
class ImgType
{
public :
    T *data;
    int width;
    int height;
    int depth;
    int step;
    int channels;
};

我分別用x方向 y方向的高斯模糊來實現ip

template<typename Type>
void ImgAlgorithm<Type>::GaussianSmooth(ImgType<Type> *src,ImgType<Type> *&dst,double sigma)
{
    sigma=sigma>0?sigma:-sigma;
    //二維高斯和矩陣大小爲 (6*sigma+1)*(6*sigma+1)
    //ksize爲奇數
    int ksize = ((int)(sigma*3+0.5))*2+1;

    if(ksize==1)
    {
        dst=src;
        return;
    }

    //計算一維高斯核 G(r) = 1/sqrt(2*pi*sigma) * exp( -r*r/(2*sigma*sigma))
    double *kernel = new double[ksize];
    double scale = -0.5/(sigma*sigma);
    double cons = sqrt(-scale/PI);

    double sum = 0;
    int kcenter = ksize/2;
    for(int i=0;i<ksize;i++)
    {
        int x=i-kcenter;
        kernel[i]=cons*exp(x*x*scale);
        sum+=kernel[i];
    }
    //歸一化,確保高斯權重在[0,1]之間
    printf("..gauss kernel:\n");
    printf("...sigma=%lf , kernelSize=%d\n",sigma,ksize);
    for(int i=0;i<ksize;i++)
    {
        kernel[i]/=sum;
        printf("...kernel[%d]=%lf\n",i,kernel[i]);
    }
    printf("kcenter %d\n",kcenter);

    dst=CreateImage(src->width,src->height,src->depth,src->channels);

    ImgType<Type> *tmp=CreateImage(src->width,src->height,src->depth,src->channels);
    
    Type a[3];//通道
    //x 方向一維高斯模糊
    for(int i=0;i<src->height;i++)
    {
        for(int j=0;j<src->width;j++)
        {
            a[0]=a[1]=a[2]=0;
            for(int k=0;k<src->channels;k++)
            {
                double sum=0;
                for(int d=-kcenter;d<=kcenter;d++)
                {
                    if(d+j>=0 && d+j<src->width)
                    {
                        a[k] += src->data[i*src->step+(d+j)*src->channels+k] * kernel[kcenter+d];
                        sum += kernel[kcenter+d];
                    }
                }
                tmp->data[i*src->step+j*src->channels+k]=a[k]/sum;
            }
        }
    }
    
    //y方向高斯模糊
    for(int i=0;i<src->height;i++)
    {
        for(int j=0;j<src->width;j++)
        {
            a[0]=a[1]=a[2]=0;
            for(int k=0;k<src->channels;k++)
            {
                double sum=0;
                for(int d=-kcenter;d<=kcenter;d++)
                {
                    if(d+i>=0 && d+i<src->height)
                    {
                        a[k] += tmp->data[(d+i)*src->step+j*src->channels+k] * kernel[kcenter+d];
                        sum += kernel[kcenter+d];
                    }
                }
                dst->data[i*src->step+j*src->channels+k]=a[k]/sum;
            }
        }
    }
    delete []kernel;
    FreeImage(tmp);
}

 

1x5高斯模糊矩陣值:

相關文章
相關標籤/搜索