双边滤波(Bilateral Filtering)

这篇具有很好参考价值的文章主要介绍了双边滤波(Bilateral Filtering)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

双边滤波(Bilateral Filtering)

1、基本思路

双边滤波(Bilateral Filtering)的基本思路是同时考虑像素点的空域信息和值域信息。即先根据像素值对要用来进行滤波的邻域做一个分割或分类,再给该点所属的类别相对较高的权重,然后进行邻域加权求和,得到最终结果。

2、实现原理

在 Bilateral Filtering 中,两个要素即:空域和值域 ,其数学表达方式相近,如下:

其中积分号前面k为归一化因子,这是考虑对所有的像素点进行加权,c 和 s 是closeness 和 similarity函数,x代表要求的点,f(x)代表该点的像素值。f(x) -->h(x)为滤波前后的图像,我们最后的滤波函数为:

由于空域部分,使得滤波特性较好,由于值域部分,使得边缘保持较好。

下图示意了有边缘的时候的权重和最后的滤波结果,可以看出权重在边界有很明显的分界,从而几乎只对自己所属的边缘一侧的像素点进行加权。

双边滤波(Bilateral Filtering)

实现 c 和 s 两个函数的一种方法即 Gaussian 核,决定其性质的为各自的sigma参数,即 σd 和 σr

其中,其中,

3、参数讨论

对于空域的Gaussian滤波不需要过多介绍,对于值域滤波,即不考虑空间只考虑像素点的相似性进行加权的结果,值域滤波只是对待滤波图像的直方图的一个变换,而对于单峰值的直方图,值域滤波将值域范围向着峰值的中间即均值方向压缩。

对于参数的选取,进行如下讨论:

首先,两个 sigma 值为 kernel 的方差,方差越大,说明权重差别越小,因此表示不强调这一因素的影响,反之,则表示更强调这一因素导致的权重的不均衡。因此:

  • 两个方面的某个的 sigma 相对变小 表示这一方面相对较重要,得到强调。如 sigma_d 变小,表示更多采用近邻的值作平滑,说明图像的空间信息更重要,即相近相似。如 sigma_r 变小,表示和自己同一类的条件变得苛刻,从而强调值域的相似性。

其次,sigma_d 表示的是空域的平滑,因此对于没有边缘的,变化慢的部分更适合;sigma_r 表示值域的差别,因此强调这一差别,即减小 sigma_r 可以突出边缘。

  • sigma_d 变大,图像每个区域的权重基本都源于值域滤波的权重,因此对于空间邻域信息不是很敏感;sigma_r 变大,则不太考虑值域,权重多来自于空间距离,因此近似于普通的高斯滤波,图像的保边性能下降。因此如果像更多的去除平滑区域的噪声,应该提高 sigma_d ,如果像保持边缘,则应该减小 sigma_r 。

  • 极端情况,如果 sigma_d 无穷大,相当于值域滤波;sigma_r 无穷大,相当于空域高斯滤波。

双边滤波(Bilateral Filtering)

4、离散数学公式模型

其中,和分别是空间域和值域的滤波参数(不确定度),和分别是像素点、的像素值。归一化权重系数为:

双边滤波的核函数是空间域核和像素值域核的综合结果:在图像的平坦区域,像素值变化很小,对应的像素值域权重接近于1,此时空间域权重起主要作用,相当于高斯模糊;在图像的边缘区域,像素值变化很大,像值域权重变大,从而保持了边缘的信息。文章来源地址https://www.toymoban.com/news/detail-458021.html

5、双边滤波代码实现

 void BilateralFilter( 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;
             }
         }
     }
 }
 ​

到了这里,关于双边滤波(Bilateral Filtering)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 均值滤波(Mean filtering)

     均值滤波是典型的 线性滤波算法 ,是指用当前像素点周围nxn个像素值的均值来代替当前像素值。使用该方法遍历处理图像内的每一个像素点,可完成整幅图像的均值滤波。  如图2-1,我们对第5行第5列的像素点进行均值滤波时,首先需要考虑需要对周围多少个像素点去取

    2024年02月04日
    浏览(25)
  • 滤波笔记一:卡尔曼滤波(Kalman Filtering)详解

    本笔记是总结了B站DR_CAN的卡尔曼滤波器的课程,他的B站主页为:DR_CAN的个人空间_哔哩哔哩_bilibili PS:虽然我不是学自控的,但是老师真的讲的很好!  一个补充的参考链接,能够帮助进一步了解Q、R对这个实验的影响: 关于卡尔曼滤波中协方差矩阵Q,R的一些思考,卡尔曼原理

    2024年02月03日
    浏览(50)
  • OpenCV图像模糊:高斯滤波、双边滤波

    1.高斯滤波原理 图像处理中,高斯滤波主要可以使用两种方法实现。一种是离散化窗口滑窗卷积,另一种方法是通过傅里叶变化。离散化窗口划船卷积时主要利用的是高斯核, 高斯核的大小为奇数 ,因为高斯卷积会在其覆盖区域的中心输出结果。常用的高斯模板有如下几种

    2024年02月07日
    浏览(46)
  • OpenCV 入门教程:中值滤波和双边滤波

    在图像处理和计算机视觉领域,中值滤波和双边滤波是两种常见的滤波方法,用于平滑图像、去除噪声等。 OpenCV 提供了中值滤波和双边滤波的实现函数,使得图像处理更加灵活和高效。本文将以中值滤波和双边滤波为中心,为你介绍使用 OpenCV 进行滤波操作的基本步骤和实例

    2024年02月13日
    浏览(35)
  • 图像处理:双边滤波算法

    今天主要是回顾一下双边滤波,我曾经在这篇——图像处理:推导五种滤波算法中推导过它,其中包含了我自己写的草稿图。 目录 双边滤波算法原理 (1)空间域核  (2)值域核 理解双边滤波 空域权重​编辑和值域权重​编辑的意义 Opencv实现双边滤波 双边滤波代码实现

    2024年02月02日
    浏览(47)
  • opencv-双边滤波

    双边滤波(Bilateral Filter)是非线性滤波中的一种。这是一种结合图像的空间邻近度与像素值相似度的处理办法。在滤波时,该滤波方法同时考虑空间临近信息与颜色相似信息,在滤除噪声、平滑图像的同时,又做到边缘保存。 双边滤波采用了两个高斯滤波的结合。一个负责

    2024年02月06日
    浏览(32)
  • OpenCV——双边滤波

    OpenCV——双边滤波由CSDN点云侠原创。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫与GPT。    双边滤波是一种综合考虑滤波器内图像空域信息和滤波器内图像像素灰度值相似性的滤波算法,可以实现在保留区域信息的基础上实现对噪声的去除、对局

    2024年01月18日
    浏览(70)
  • 双边滤波原理和实现

             双边滤波(Bilateral filter)是一种非线性的滤波方法,是结合图像的空间邻近度和像素值相似度的一种折衷处理,同时考虑空域信息和灰度相似性,达到保边去噪的目的。 双边滤波器之所以能够做到在平滑去噪的同时还能够很好的保存边缘(Edge Preserve),是由于其

    2024年02月08日
    浏览(25)
  • OpenCV-24双边滤波

    双边滤波对于图像的边缘信息能够更好的保存。其原理为一个与 空间距离 相关的高斯函数与一个 灰度距离 相关的高斯函数相乘。 空间距离 :指的是当前点与中心点的欧式距离。空间域的高斯函数及其数学形式为: 其中(xi,yi)为当前点的位置,(xc,yc)为中心点位置,

    2024年01月17日
    浏览(35)
  • Opencv之图像滤波:6.双边滤波(cv2.bilateralFilter)

            前面我们介绍的滤波方法都会对图像造成模糊,使得边缘信息变弱或者消失,因此需要一种能够对图像边缘信息进行保留的滤波算法,双边滤波是综合考虑空间信息和色彩信息的滤波方式,在滤波过程中能够有效地保护 图像内的边缘信息。         之前介绍的

    2024年02月05日
    浏览(50)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包