图像降噪算法——中值滤波/均值滤波/高斯滤波/双边滤波

图像降噪算法——中值滤波/均值滤波/高斯滤波/双边滤波

图像降噪算法——中值滤波/均值滤波/高斯滤波/双边滤波

空间域滤波器是最传统最简单的一类图像降噪算法,简单到我都有点不太想做写这篇博客(傲娇了…),但是为了内容的完整性,我还是在此总结下,空间域滤波器可以分为局部滤波器非局部滤波器,其中局部滤波器又分为线性滤波器非线性滤波器。本博客介绍几种比较经典的局部滤波器:中值滤波、均值滤波、高斯滤波、双边滤波。其中均值滤波和高斯滤波为线性滤波器,中值滤波和双边滤波为非线性滤波。

1. 基本原理

因为这些滤波器原理相对都比较简单,因为以我的理解简单描述下:
(1) 中值滤波
以目标像素周围 3 × 3 3\times3 3×3的邻域为例,就是将 3 × 3 3\times3 3×3邻域中九个像素灰度值进行排序,将中间灰度值作为目标像素的灰度值。椒盐噪声影响的像素的灰度值通常都非常大或者非常小,因此通过排序会被消除掉。

(2) 均值滤波
同样以目标像素周围 3 × 3 3\times3 3×3的邻域为例,就是将 3 × 3 3\times3 3×3邻域中九个像素灰度值的平均值作为目标像素的灰度值

(3) 高斯滤波
高斯滤波就是将均值滤波中的平局值改为高斯加权平均值,邻域中年距离目标像素越远的像素灰度值权重越小,通常通过生成一个高斯模板实现

(4) 双边滤波
双边滤波是在高斯滤波的基础上在权重设计中进一步考虑了像素灰度梯度的影响,首先考虑高斯部分权重(下图中的Spatial weight): w d ( i , j , k , l ) = exp ⁡ ( − ( i − k ) 2 + ( j − l ) 2 2 σ d 2 ) w_{d}(i, j, k, l)=\exp \left(-\frac{(i-k)^{2}+(j-l)^{2}}{2 \sigma_{d}^{2}}\right) wd(i,j,k,l)=exp(2σd2(ik)2+(jl)2)然后考虑像素灰度梯度部分权重(下图中的Range weight): w r ( i , j , k , l ) = exp ⁡ ( − ∥ f ( i , j ) − f ( k , l ) ∥ 2 2 σ r 2 ) w_{r}(i, j, k, l)=\exp \left(-\frac{\|f(i, j)-f(k, l)\|^{2}}{2 \sigma_{r}^{2}}\right) wr(i,j,k,l)=exp(2σr2f(i,j)f(k,l)2)其中 ( i , j ) (i,j) (i,j)为模板中邻域像素坐标, ( i , j ) (i,j) (i,j)为模板中心像素坐标, f ( i , j ) f(i,j) f(i,j)为坐标 ( i , j ) (i,j) (i,j)处的像素值, σ d \sigma_d σd σ r \sigma_r σr分别为两个权重的方差,将两部分权重相乘即获得双边滤波的权重: w ( i , j , k , l ) = w d ( i , j , k , l ) ∗ w r ( i , j , k , l ) = exp ⁡ ( − ( i − k ) 2 + ( j − l ) 2 2 σ d 2 − ∥ f ( i , j ) − f ( k , l ) ∥ 2 2 σ r 2 ) w(i, j, k, l)=w_{d}(i, j, k, l) * w_{r}(i, j, k, l)=\exp \left(-\frac{(i-k)^{2}+(j-l)^{2}}{2 \sigma_{d}^{2}}-\frac{\|f(i, j)-f(k, l)\|^{2}}{2 \sigma_{r}^{2}}\right) w(i,j,k,l)=wd(i,j,k,l)wr(i,j,k,l)=exp(2σd2(ik)2+(jl)22σr2f(i,j)f(k,l)2)可以参看下图进行理解:

在这里插入图片描述

2. C++代码实现

下面是基于OpenCV对以上四种滤波器的实现:

Mat Denoise::MedeanFilter(const Mat &src, int size)
{
    Mat dst = src.clone();
    int start = size/2;
    for(int i = start; i < dst.rows-start; i++)
    {
        for(int j = start; j < dst.cols-start; j++)
        {
            vector<uchar> model;
            for(int m = i-start; m <= i+start; m++)
            {
                for(int n = j-start; n <= j+start; n++)
                {
                    model.push_back(src.at<uchar>(m,n));
                }
            }
            sort(model.begin(), model.end());
            dst.at<uchar>(i,j) = model[size*size/2];
        }
    }
    return dst;
}

//均值滤波
Mat Denoise::MeanFilter(const Mat &src, int size)
{
    Mat dst = src.clone();
    int start = size/2;
    for(int i = start; i < dst.rows-start; i++)
    {
        for(int j = start; j < dst.cols-start; j++)
        {
            int sum = 0;
            for(int m = i-start; m <= i+start; m++)
            {
                for(int n = j-start; n <= j+start; n++)
                {
                   sum += src.at<uchar>(m,n);
                }
            }
            dst.at<uchar>(i,j) = (uchar)(sum/size/size);
        }
    }
    return dst;
}

//高斯滤波
Mat Denoise::GaussianFilter(const Mat &src, int size, double sigma)
{
    vector<vector<double>> gaussianTemplate = GaussianTemplate(size, sigma);
    Mat dst = src.clone();
    int start = size/2;
    for(int i = start; i < dst.rows-start; i++)
    {
        for(int j = start; j < dst.cols-start; j++)
        {
            int sum = 0;
            for(int m = i-start; m <= i+start; m++)
            {
                for(int n = j-start; n <= j+start; n++)
                {
                    sum += src.at<uchar>(m,n)*gaussianTemplate[m-i+start][n-j+start];
                }
            }
            dst.at<uchar>(i,j) = (uchar)sum;
        }
    }
    return dst;
}

vector<vector<double>> Denoise::GaussianTemplate(int size, double sigma)
{
    vector<vector<double>> temp;
    double base = 1.0 / 2.0 / CV_PI / sigma / sigma;
    for(int i = 0; i < size; i++)
    {
        vector<double> vec;
        for(int j = 0; j < size; j++)
        {
            double a = (pow(i - size/2, 2) + pow(j - size/2, 2)) / 2.0 / sigma / sigma;
            double b = base * exp(-a);
            vec.push_back(b);
        }
        temp.push_back(vec);
    }
    return temp;
}

//双边滤波
Mat Denoise::BilateralFilter(const Mat &src, int size, double sigmaD, double sigmaR)
{
    vector<vector<double>> tempD;
    vector<double> tempR;
    Mat dst = src.clone();

    //生成定义域模板
    for(int i = 0; i < size; i++)
    {
        vector<double> vec;
        for(int j = 0; j < size; j++)
        {
            double a = (pow(i - size/2, 2) + pow(j - size/2, 2)) / 2.0 / sigmaD / sigmaD;
            double b = exp(-a);
            vec.push_back(b);
        }
        tempD.push_back(vec);
    }

    //生成值域模板
    for(int i = 0; i < 256; i++)
    {
        double a = (i * i / 2.0 / sigmaR / sigmaR);
        double b = exp(-a);
        tempR.push_back(b);
    }

    int start = size/2;
    for(int i = start; i < dst.rows-start; i++)
    {
        for(int j = start; j < dst.cols-start; j++)
        {
            double sum = 0;
            double weightSum = 0;
            for(int m = i-start; m <= i+start; m++)
            {
                for(int n = j-start; n <= j+start; n++)
                {
                    double weight = tempD[m-i+start][n-j+start] * tempR[abs(src.at<uchar>(m,n)-src.at<uchar>(i,j))];
                    sum += src.at<uchar>(m,n)*weight;
                    weightSum += weight;
                }
            }
            dst.at<uchar>(i,j) = (uchar)sum/weightSum;
        }
    }
    return dst;
}

运行结果如下:
首先,原图如下图所示:在这里插入图片描述
我们首先看看中值滤波椒盐噪声的效果:
添加椒盐噪声后图像如下:
在这里插入图片描述
中值滤波后效果如下:
在这里插入图片描述
然后我们来对比下均值滤波高斯滤波双边滤波高斯噪声的效果:
添加高斯噪声的图像如下:在这里插入图片描述
均值滤波后效果如下:
在这里插入图片描述
高斯滤波后效果如下:
在这里插入图片描述
双边滤波效果如下:
在这里插入图片描述

3. 结论

  1. 对于椒盐噪声,中值滤波的效果是可以接受的,但是不可避免地也带来了边缘模糊的问题。
  2. 对于高斯噪声,高斯滤波和双边滤波效果上肉眼看上去可能差不多,但都比均值滤波要好,但是毕竟局部空间域算法比较简单,咱不能要求太高。

有问题欢迎交流~

此外,这里我写一个各种算法的总结目录图像降噪算法——图像降噪算法总结,对图像降噪算法感兴趣的同学欢迎参考

  • 8
    点赞
  • 103
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值