双边滤波算法原理及实现

双边滤波算法原理

双边滤波是一种非线性滤波器,它可以达到保持边缘、降噪平滑的效果。和其他滤波原理一样,双边滤波也是采用加权平均的方法,用周边像素亮度值的加权平均代表某个像素的强度,所用的加权平均基于高斯分布[1]。最重要的是,双边滤波的权重不仅考虑了像素的欧氏距离(如普通的高斯低通滤波,只考虑了位置对中心像素的影响),还考虑了像素范围域中的辐射差异(例如卷积核中像素与中心像素之间相似程度、颜色强度,深度距离等),在计算中心像素的时候同时考虑这两个权重。

双边滤波的核函数是空间域核与像素范围域核的综合结果:在图像的平坦区域,像素值变化很小,对应的像素范围域权重接近于1,此时空间域权重起主要作用,相当于进行高斯模糊;在图像的边缘区域,像素值变化很大,像素范围域权重变大,从而保持了边缘的信息。

双边滤波器代码实现

void cv::bilateralFilter( InputArray _src, OutputArray _dst, int d,
                      double sigmaColor, double sigmaSpace,
                      int borderType )
{
    Mat src = _src.getMat();
    _dst.create( src.size(), src.type() );
    Mat dst = _dst.getMat();

    if( src.depth() == CV_8U )
        bilateralFilter_8u( src, dst, d, sigmaColor, sigmaSpace, borderType );
    else if( src.depth() == CV_32F )
        bilateralFilter_32f( src, dst, d, sigmaColor, sigmaSpace, borderType );
    else
        CV_Error( CV_StsUnsupportedFormat,
        "Bilateral filtering is only implemented for 8u and 32f images" );
}

static void
bilateralFilter_8u( const Mat& src, Mat& dst, int d,
    double sigma_color, double sigma_space,
    int borderType )
{

    int cn = src.channels();
    int i, j, k, maxk, radius;
    Size size = src.size();

    CV_Assert( (src.type() == CV_8UC1 || src.type() == CV_8UC3) &&
              src.type() == dst.type() && src.size() == dst.size() &&
              src.data != dst.data );

    if( sigma_color <= 0 )
        sigma_color = 1;
    if( sigma_space <= 0 )
        sigma_space = 1;

    // 计算颜色域和空间域的权重的高斯核系数, 均值 μ = 0;  exp(-1/(2*sigma^2))
    double gauss_color_coeff = -0.5/(sigma_color*sigma_color);
    double gauss_space_coeff = -0.5/(sigma_space*sigma_space);

    // radius 为空间域的大小: 其值是 windosw_size 的一半
    if( d <= 0 )
        radius = cvRound(sigma_space*1.5);
    else
        radius = d/2;
    radius = MAX(radius, 1);
    d = radius*2 + 1;

    Mat temp;
    copyMakeBorder( src, temp, radius, radius, radius, radius, borderType );

    vector<float> _color_weight(cn*256);
    vector<float> _space_weight(d*d);
    vector<int> _space_ofs(d*d);
    float* color_weight = &_color_weight[0];
    float* space_weight = &_space_weight[0];
    int* space_ofs = &_space_ofs[0];

    // 初始化颜色相关的滤波器系数: exp(-1*x^2/(2*sigma^2))
    for( i = 0; i < 256*cn; i++ )
        color_weight[i] = (float)std::exp(i*i*gauss_color_coeff);

    // 初始化空间相关的滤波器系数和 offset:
    for( i = -radius, maxk = 0; i <= radius; i++ )
    {
        j = -radius;

        for( ;j <= radius; j++ )
        {
            double r = std::sqrt((double)i*i + (double)j*j);
            if( r > radius )
                continue;
            space_weight[maxk] = (float)std::exp(r*r*gauss_space_coeff);
            space_ofs[maxk++] = (int)(i*temp.step + j*cn);
        }
    }

    // 开始计算滤波后的像素值
    for( i = 0; i < 0, size.height; i++ )
    {
        const uchar* sptr = temp->ptr(i+radius) + radius*cn;  // 目标像素点
        uchar* dptr = dest->ptr(i);

        if( cn == 1 )
        {
            // 按行开始遍历
            for( j = 0; j < size.width; j++ )
            {
                float sum = 0, wsum = 0;
                int val0 = sptr[j];

                // 遍历当前中心点所在的空间邻域
                for( k = 0; k < maxk; k++ )
                {
                    int val = sptr[j + space_ofs[k]];
                    float w = space_weight[k]*color_weight[std::abs(val - val0)];
                    sum += val*w;
                    wsum += w;
                }

                // 这里不可能溢出, 因此不必使用 CV_CAST_8U.
                dptr[j] = (uchar)cvRound(sum/wsum);
            }
        }
        else
        {
            assert( cn == 3 );
            for( j = 0; j < size.width*3; j += 3 )
            {
                float sum_b = 0, sum_g = 0, sum_r = 0, wsum = 0;
                int b0 = sptr[j], g0 = sptr[j+1], r0 = sptr[j+2];
                k = 0;

                for( ; k < maxk; k++ )
                {
                    const uchar* sptr_k = sptr + j + space_ofs[k];
                    int b = sptr_k[0], g = sptr_k[1], r = sptr_k[2];
                    float w = space_weight[k]*color_weight[std::abs(b - b0) +
                                                            std::abs(g - g0) + std::abs(r - r0)];
                    sum_b += b*w; sum_g += g*w; sum_r += r*w;
                    wsum += w;
                }
                wsum = 1.f/wsum;
                b0 = cvRound(sum_b*wsum);
                g0 = cvRound(sum_g*wsum);
                r0 = cvRound(sum_r*wsum);
                dptr[j] = (uchar)b0;
                dptr[j+1] = (uchar)g0;
                dptr[j+2] = (uchar)r0;
            }
        }
    }
}

参考

[1]: Bilateral Filters(双边滤波算法)原理及实现

[2]: 双边滤波算法介绍与实现

原文地址:https://www.cnblogs.com/magic-428/p/9172406.html

时间: 2024-10-10 16:21:30

双边滤波算法原理及实现的相关文章

图像平滑技术之盒滤波、均值滤波、中值滤波、高斯滤波、双边滤波的原理概要及OpenCV代码实现

图像平滑是指直接对源图像的每个像素数据做邻域运算以达到平滑图像的目的.实质上主要就是通达卷积核算子实现的,卷积核算子的相关知识大家可以参考我写的博文http://blog.csdn.net/wenhao_ir/article/details/51691410 图像平滑也称为模糊或滤波,是图像处理中常用的技术之一,进行平滑处理时需要用到滤波器核(其实就是卷积核算子),根据滤波器核函数来实现不同的滤波技术.下面介绍几种 常用的图像平滑方法的大概原理及OpenCV下的实现代码. 一.盒滤波(均值滤波)

Bilateral Filtering(双边滤波)算法研究

1. 简介 图像平滑是一个重要的操作,而且有多种成熟的算法.这里主要简单介绍一下Bilateral方法(双边滤波),这主要是由于前段时间做了SSAO,需要用bilateral blur 算法进行降噪.Bilateral blur相对于传统的高斯blur来说很重要的一个特性即可可以保持边缘(Edge Perseving),这个特点对于一些图像模糊来说很有用.一般的高斯模糊在进行采样时主要考虑了像素间的空间距离关系,但是却并没有考虑像素值之间的相似程度,因此这样我们得到的模糊结果通常是整张图片一团模

双边滤波算法的简易实现bilateralFilter

没怎么看过双边滤波的具体思路,动手写一写,看看能不能突破一下. 最后,感觉算法还是要分开 水平 与 垂直 方向进行分别处理,才能把速度提上去. 没耐性写下去了,发上来,给大伙做个参考好了. 先上几张效果图. 半径参数为10. 见图,磨皮降噪效果还不错. 具体代码如下: void bilateralFilter(unsigned char* pSrc, unsigned char* pDest, int width, int height, int radius) { float delta =

图像处理之滤波算法

一.学习心得: 在我学习基本滤波算法原理的时候,因为刚接触不是很理解算法具体是怎样实现的,不过在学习了图像形态学之后,发现滤波算法其实很简单.所以在此建议初学者在学习滤波算法之前,可以先学习一下图像形态学,会达到事半功倍的效果. 二.对于滤波功能的理解: 滤波算法,可以理解成一种过滤算法,就像我们筛选产品时,把次品去除掉,只留下合格的产品.而在图像处理中的滤波算法中,处理的对象是图像,除了去除掉图像中不想要的像素点的值(如去除噪声),还可以加强图像中我们需要研究一些内容(如边缘提取). 三.滤波

OpenCV学习笔记(27)KAZE 算法原理与源码分析(一)非线性扩散滤波

http://blog.csdn.net/chenyusiyuan/article/details/8710462 OpenCV学习笔记(27)KAZE 算法原理与源码分析(一)非线性扩散滤波 2013-03-23 17:44 16963人阅读 评论(28) 收藏 举报 分类: 机器视觉(34) 版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[+] KAZE系列笔记: OpenCV学习笔记(27)KAZE 算法原理与源码分析(一)非线性扩散滤波 OpenCV学习笔记(28)KA

双边滤波原理与C++实现

一.原理 双边滤波(Bilateral filter)是一种可以去噪保边的滤波器.之所以可以达到此效果,是因为滤波器是由两个函数构成:一个函数是由几何空间距离决定滤波器系数,另一个由像素差值决定滤波器系数. 原理示意图如下: 双边滤波器中,输出像素的值依赖于邻域像素的值的加权组合, 权重系数w(i,j,k,l)取决于定义域核 和值域核 的乘积 二.C++实现 2.1 OpenCV调用方法: cvSmooth(m_iplImg, dstImg, CV_BILATERAL, 2 * r + 1, 0

双边滤波和引导滤波的原理

双边滤波很有名,使用广泛,简单的说就是一种同时考虑了像素空间差异与强度差异的滤波器,因此具有保持图像边缘的特性. 先看看我们熟悉的高斯滤波器 其中W是权重,i和j是像素索引,K是归一化常量.公式中可以看出,权重只和像素之间的空间距离有关系,无论图像的内容是什么,都有相同的滤波效果. 再来看看双边滤波器,它只是在原有高斯函数的基础上加了一项,如下 其中 I 是像素的强度值,所以在强度差距大的地方(边缘),权重会减小,滤波效应也就变小.总体而言,在像素强度变换不大的区域,双边滤波有类似于高斯滤波的效

由Photoshop高反差保留算法原理联想到的一些图像增强算法。

原地址:http://blog.csdn.net/laviewpbt/article/details/20577683 关于高反差保留的用处说明呢,从百度里复制了一段文字,我觉得写得蛮好的: 高反差保留就是保留图像的高反差部分,再说得真白些,就是保留图像上像素与周围反差比较大的部分,其它的部分都变为灰色.拿一个人物照片来举例,反差比较大的部分有人的眼睛,嘴,以及身体轮廓.如果执行了就反差保留,这些信息将留下来(与灰色形成鲜明对比).它的主要作用就是加强图像中高反差部分.还以人物照片为例子,一般为

双边滤波

Qt 平台,双边滤波原理代码例如以下: #include <QCoreApplication> #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <iostream> #include <cmath> using namespace cv; usi