图像处理-双边滤波原理

来源:互联网 发布:linux 安装 jdk 编辑:程序博客网 时间:2024/06/05 11:19
     双边滤波(Bilateral filter)是一种可以去噪保边的滤波器。之所以可以达到此效果,是因为滤波器是由两个函数构成:一个函数是由几何空间距离决定滤波器系数,另一个由像素差值决定滤波器系数。
 原理示意图如下:

技术分享

     双边滤波器中,输出像素的值依赖于邻域像素的值的加权组合,
          技术分享
     权重系数w(i,j,k,l)取决于定义域核
          技术分享
     和值域核
          技术分享
     的乘积
          技术分享

二、C++实现
     2.1 OpenCV调用方法:

cvSmooth(m_iplImg, dstImg, CV_BILATERAL, 2 * r + 1, 0, sigma_r, sigma_d);


     2.3 C++代码
     
//双边滤波
void CImgPrcView::BilateralFilter()
{
    // TODO: 在此添加命令处理程序代码
    if (!m_pBitmap) return;
    FreeInterResultImage();

    int r = 7;//滤波器边长
    int w_filter = 2 * r + 1;
    //修改该参数
    double sigma_d = 5;
    double sigma_r = 25;
    int nx = m_dwWidth, ny = m_dwHeight;
    double gaussian_d_coeff = -1 / (2 * sigma_d * sigma_d);    //定义域核 sigma_d为标准差
    double gaussian_r_coeff = -1 / (2 * sigma_r * sigma_r);    //值域核    sigma_r为标准差
    double *d_metrix = new double[w_filter * w_filter];            // spatial weight 空间距离系数
    double *r_metrix = new double[w_filter * w_filter];            // r_metrix weight 空间距离系数
    double *metrix = new double[w_filter * w_filter];            // metrix weight 空间距离系数

    //double r_metrix[256];  // similarity weight 灰度差值系数

    // copy the original image
    BYTE *img_tmp = new BYTE[nx * ny];
    BYTE *img = new BYTE[nx * ny];
    for (int i = 0; i < ny; i++)
        for (int j = 0; j < nx; j++)
            {
                img_tmp[i * nx + j] = m_pBitmap[i * nx + j];
                img[i * nx + j] = 255;
            }

    // compute spatial weight
    for (int i = -r; i <= r; i++)
        for (int j = -r; j <= r; j++)
        {
             d_metrix[(i + r) * w_filter + (j + r)] = exp((i * i + j * j) * gaussian_d_coeff);
        }

// bilateral filter
    for (int i = 0; i < ny; i++)
    {
        for (int j = 0; j < nx; j++)
        {
            // compute similarity weight
            double weight_temp = 0;
            for (int k = -r; k <= r; k++)
            {
                for (int l = -r; l <= r; l++)
                {
                    if (((i + k) < 0) || ((i + k) > ny) || ((j + l) < 0) || ((j + l) > nx))
                    {
                        weight_temp = abs(img_tmp[i * nx + j] - 0);
                        r_metrix[(k + r)*(2 * r + 1) + (l + r)] = exp(gaussian_r_coeff * pow(weight_temp, 2));
                    }
                    else
                    {
                        weight_temp = abs(img_tmp[i * nx + j] - img_tmp[(i + k) * nx + (j + l)]);
                        r_metrix[(k + r)*(2 * r + 1) + (l + r)] = exp(gaussian_r_coeff * pow(weight_temp , 2));
                    }
                }
            }

            // compute weight               
            double weight_up = 0, weight_down = 0;
            for (int k = -r; k <= r; k++)
            {
                for (int l = -r; l <= r; l++)
                {
                    if (((i + k) < 0) || ((i + k) > ny) || ((j + l) < 0) || ((j + l) > nx))
                    {
                        metrix[(k + r) * (2 * r + 1) + (l + r)] = 0;
                        //计算当前灰度值
                        weight_down += metrix[(k + r) * (2 * r + 1) + (l + r)];
                        weight_up += metrix[(k + r) * (2 * r + 1) + (l + r)] * 0/* * img_tmp[(i) * nx + (j)]*/; //边界处理
                    }
                    else
                    {
                        metrix[(k + r) * (2 * r + 1) + (l + r)] = r_metrix[(k + r) * (2 * r + 1) + (l + r)] * d_metrix[(k + r) * (2 * r + 1) + (l + r)];
                        //计算当前灰度值
                        weight_down += metrix[(k + r) * (2 * r + 1) + (l + r)];
                        weight_up += metrix[(k + r) * (2 * r + 1) + (l + r)] * img_tmp[(i + k) * nx + (j + l)];
                    }
                }
            }
            img[i * nx + j] = weight_up / weight_down;
        }
    }
    AddInterResultImage(img, m_dwHeight, m_dwWidth, 8, "双边滤波");
    Invalidate(FALSE);
    UpdateWindow();
    delete [] img;
    delete [] img_tmp;
    delete [] d_metrix;
    delete [] r_metrix;
    delete [] metrix;
}
性能方面,跟OpenCV处理速度有差距,有兴趣的,可以自己研究OpenCV版本的源代码

三、效果图




四、参考资料
     资料[4]是MIT的学习资料,最全面,包括课件、论文、代码等,涵盖原理、改进、应用、与PDE的联系等等,最值得一看。

[1] 双边滤波器的原理及实现[Rachel-Zhang]
[2]【OpenCV】邻域滤波:方框、高斯、中值、双边滤波
[3] Bilateral Filtering(双边滤波) for SSAO
[4]MIT学习资料
原创粉丝点击