数字图像处理(九)双边滤波

article/2025/10/26 5:54:53

文章目录


一、何为双边滤波?

  双边滤波(Bilateral filter)是一种非线性的滤波方法,是结合图像的空间邻近度和像素值相似度的一种折中滤波方法。
  线性滤波的含义: g ( i , j ) = T [ f ( i , j ) ] g(i,j)=T[f(i,j)] g(i,j)=T[f(i,j)],其中 T T T是线性算子。即输入图像的像素值经过线性变换得到输出图像的像素值,例如:均值滤波、高斯滤波等。线性滤波器的原始数据与滤波结果是一种算数运算,即用加减乘除等运算实现。由于线性滤波器是算数运算,所以有固定的模板。
  非线性滤波的含义:非线性滤波的算子中包含了取绝对值、置零等非线性运算。例如:最大值滤波器、中值滤波器等。非线性滤波器的原始数据与滤波结果是一种逻辑关系,是通过比较一定邻域内的灰度值大小来实现的,没有固定的模板。

二、为什么要使用双边滤波?

  中值滤波、高斯滤波、维纳滤波等滤波方法容易模糊图片的边缘细节,对高频细节的保护效果并不明显。相较而言,双边滤波器可以很好的在降噪的同时保护边缘。
  双边滤波的卷积核是非线性的,因此计算复杂度高。不同位置的卷积核不同,所以不能预先计算或者执行FFT,计算起来比较费时。

三、双边滤波原理

1.空间域核

  空间域核模板权重 w d w_d wd如下。
w d ( i , j , k , l ) = e x p ( − ( i − k ) 2 + ( j − l ) 2 2 σ d 2 ) w_d(i,j,k,l)=exp(-\frac{(i-k)^2+(j-l)^2}{2\sigma^2_d}) wd(i,j,k,l)=exp(2σd2(ik)2+(jl)2)
w d w_d wd表示了邻域内某点 q ( k , l ) q(k,l) q(k,l)与中心点 p ( i , j ) p(i,j) p(i,j)的欧氏距离。 σ d \sigma_d σd为高斯函数的标准差。使用该公式生成的滤波器模板和高斯滤波器使用的模板是没有区别的。

2.值域核

  值域核的模板权重 w r w_r wr如下。
w r ( i , j , k , l ) = e x p ( − ∥ f ( i , j ) − f ( k , l ) ∥ 2 2 σ r 2 ) w_r(i,j,k,l)=exp(-\frac{\Vert f(i,j)-f(k,l)\Vert^2}{2\sigma^2_r}) wr(i,j,k,l)=exp(2σr2f(i,j)f(k,l)2)
其中, f ( i , j ) f(i,j) f(i,j)表示图像在点 ( i , j ) (i,j) (i,j)处的像素值; f ( k , l ) f(k,l) f(k,l)为模板窗口中心坐标点的像素值。 σ r \sigma_r σr为高斯函数䣌标准差。

3.模板相乘

  将上述两个模板相乘就得到了双边滤波器的模板权值。
w ( i , j , k , l ) = w d ( i , j , k , l ) × w r ( i , j , k , l ) = e x p ( − ( 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)\times w_r(i,j,k,l)=exp(-\frac{(i-k)^2+(j-l)^2}{2\sigma^2_d}-\frac{\Vert f(i,j)-f(k,l)\Vert^2}{2\sigma^2_r}) 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)

滤波后的图像的像素值为: g ( i , j ) = ∑ k l f ( k , l ) w ( i , j , k , l ) ∑ k l w ( i , j , k , l ) g(i,j)=\frac{\sum_{kl}f(k,l)w(i,j,k,l)}{\sum_{kl}w(i,j,k,l)} g(i,j)=klw(i,j,k,l)klf(k,l)w(i,j,k,l)

四、 w d w_d wd w r w_r wr σ \sigma σ的理解

  空间域权值 w d w_d wd衡量的是 p , q p,q p,q两点之间的欧式距离,距离越远 w d w_d wd越小。这和高斯滤波器是相同的,高斯滤波器的像素位置越靠近中心点权重越大。
  值域权值 w r w_r wr衡量的是 p , q p,q p,q两点之间的像素值的相似程度,越相似 w r w_r wr越大。

从图像的平坦区域和边缘区域直观分析双边滤波的效果。

  • 在平坦区域,临近像素与中心像素的差值较小,对应 w r w_r wr接近1,此时空域权重 w d w_d wd起主要作用,相当于是直接使用高斯滤波器对图像进行滤波。
  • 在边缘区域灰度会有较大的变化,与被卷积像素的灰度值类似的区域的 w r w_r wr较大趋近于1,与被卷积像素的灰度值差值较大的区域的 w r w_r wr较小趋于0。这样对被卷积的像素来说,收到的影响较小,从而保持了细节信息。

   σ d \sigma_d σd选取:和高斯滤波一样, σ d \sigma_d σd越大,图像越平滑; σ d \sigma_d σd越小,中心点权重越大,周围点权重越小,对图像的滤波作用越小,趋于0时,输出等同于原图。
   σ r \sigma_r σr选取: σ r \sigma_r σr越大,边缘越模糊。当 σ r \sigma_r σr无穷大时,值域系数近似相等( e x p ( 0 ) = 1 exp(0)=1 exp(0)=1),与空间域模板相乘后可认为等效于高斯滤波。 σ r \sigma_r σr越小,边缘越清晰。当 σ r \sigma_r σr无限接近0时,值域系数除了中心位置为1,其他近似为0( e x p ( − ∞ ) = 0 exp(-\infty)=0 exp()=0),与空间域模板相乘进行滤波的结果等效于原图像。

五、C++代码实现

1.opencv中Mat的一点小知识

  在普通的C++编码中,如果我们想要通过函数改变一个类似于int、float这样的变量的值,需要将变量的地址传入到函数中。而在opencv中,如果我们想要改变一个Mat的值,只需要将Mat传入函数即可。具体的介绍请参考这里。

2.关于边界的处理

  使用滤波器对边界的像素进行处理时,滤波器会出现越界现象,此时我们用原图中与越界的点相对应的像素点进行替代。
在这里插入图片描述
如上图所示,粉色位置为要进行滤波的像素点,滤波器大小为 3 × 3 3\times 3 3×3,滤波器上编号为1的位置明显已经越界(无像素值),此时我们用编号为2的位置的像素值代替1处的像素值。

3.双边滤波代码

double Wd(const int &i, const int &j, const float &sigma_d)
{return double(exp(-(pow(i, 2) + pow(j, 2)) / (2 * pow(sigma_d, 2))));
}
double Wr(const float &x, const float &sigma_r)
{return double(exp(-(pow(x, 2) / (2 * pow(sigma_r, 2)))));
}
// 边界处理函数
int reflect(int M, int x)
{if (x < 0)return -x;if (x >= M)return 2 * M - x-1;return x;}void ValueProcess(const cv::Mat &image, cv::Mat bFilterImage, const int &x, const int &y, const int &d, const float &sigma_d, const float &sigma_r)
{int k = d / 2;double iFiltered = 0;double wP = 0;int height = image.rows;int width = image.cols;int neighbor_x = 0;int neighbor_y = 0;for (int i = -k; i <= k; i++){for (int j = -k; j <=k; j++){//构造w_d权重double wd = Wd(i, j, sigma_d);//越界处理neighbor_x = reflect(height, x + i);neighbor_y = reflect(width, y + j);//构造w_r权重double wr = Wr(image.at<uchar>(neighbor_x, neighbor_y) - image.at<uchar>(x, y), sigma_r);double w = wd * wr;iFiltered = iFiltered + image.at<uchar>(neighbor_x, neighbor_y)*w;wP = wP + w;}}iFiltered = iFiltered / wP;bFilterImage.at<double>(x, y) = iFiltered;
}cv::Mat BFilter(const cv::Mat &image, const int &d, const float &sigma_d, const float &sigma_r)
{int height = image.rows;int width = image.cols;cv::Mat bFilterImage = cv::Mat::zeros(height, width, CV_64FC1);for (int i = 0; i < height; i++){for (int j = 0; j < width; j++){//对每个像素点进行处理ValueProcess(image, bFilterImage, i, j, d, sigma_d, sigma_r);}} return bFilterImage;}int main()
{cv::Mat image = cv::imread("LenaRGB.bmp");cv::Mat grayImage;cv::cvtColor(image, grayImage, CV_BGR2GRAY);// call b filterint d = 7;float sigma_d = 12.0;float sigma_r = 16.0;cv::Mat bFilterImage = BFilter(grayImage, d, sigma_d, sigma_r);cv::convertScaleAbs(bFilterImage, bFilterImage);  // 转换到8位uchar类型return 0;
}

参考链接:

https://www.cnblogs.com/snowxshy/p/3855011.html
https://zhuanlan.zhihu.com/p/127023952
https://blog.csdn.net/leonardohaig/article/details/118058527


http://chatgpt.dhexx.cn/article/WgVyhLQh.shtml

相关文章

双边滤波(Bilateral Filtering)

双边滤波&#xff08;Bilateral Filtering&#xff09; 1、基本思路 双边滤波&#xff08;Bilateral Filtering&#xff09;的基本思路是同时考虑像素点的空域信息和值域信息。即先根据像素值对要用来进行滤波的邻域做一个分割或分类&#xff0c;再给该点所属的类别相对较高的…

三种经典图像滤波方法介绍——双边滤波(Bilateral filter)、导向滤波(Guided Fliter)、滚动导向滤波(RollingGuidedFilter)

文章目录 一、前言二、双边滤波(Bilateral filter)2.1 双边滤波的理论介绍及公式推导2.2 双边滤波的matlab程序实现 三、导向滤波(Guided Fliter)3.1 导向滤波的理论介绍及公式推导3.2 导向滤波matlab代码实现 四、滚动导向滤波(RollingGuidedFilter)4.1 滚动导向滤波的理论介绍…

图像处理:双边滤波算法

今天主要是回顾一下双边滤波&#xff0c;我曾经在这篇——图像处理&#xff1a;推导五种滤波算法中推导过它&#xff0c;其中包含了我自己写的草稿图。 目录 双边滤波算法原理 &#xff08;1&#xff09;空间域核 &#xff08;2&#xff09;值域核 理解双边滤波 空域权重​…

Bilateral Filters(双边滤波算法)的超简单原理,学不会你打我。

摘要&#xff1a; 双边滤波(Bilateral Filters)是非常常用的一种滤波&#xff0c;它可以达到保持边缘、降噪平滑的效果。和其他滤波原理一样&#xff0c;双边滤波也是采用加权平均的方法&#xff0c;用周边像素亮度值的加权平均代表某个像素的强度&#xff0c;所用的加权平均基…

jQuery源码分析理解

1&#xff1a; 首先我们先来看一下jquery代码的整体结构 代码从16行开始为真正的jquery源码&#xff0c;我们看到Jquery源码第一个()中是定义了一个匿名function( window, undefined ) {}&#xff1b;接着末尾有个(window)&#xff0c;就表示执行这个匿名function&#xff0c;…

jQuery源码分析(一)

jQuery源码分析&#xff08;一&#xff09; 我们知道在jQuery中在使用选择器或者给元素绑定事件的时候都是通过$来操作的。那么基于JavaScript面向对象的思想&#xff0c;我们可以把jQuery看做一个函数或者对象&#xff0c;它里边存储了大量的方法&#xff0c;是一个类库。 $代…

jQuery源码阅读(一)---jQuery源码整体架构

之前用jQuery库写了两个小例子&#xff08;结合Apache、PHP实现的简易聊天室以及音乐播放器&#xff09;&#xff0c;详见我的上两篇博客jQuery aJax技术以及PHP实现简单聊天室、 利用jQuery实现音乐播放器。为了更加深入了解jQuery库的架构以及巩固原生JS的基础和深度&#xf…

jquery源码解析

(function(a,b){})() JQuery源码的开头 (function(a,b){})(window)通常(function(){})()用来封装一些私有成员或者公共成员的导出。 1. 定义一个匿名函数&#xff0c;创建了一个“私有”的命名空间&#xff0c;该命名空间的变量和方法&#xff0c;不会破坏全局的命名空间。确…

jQuery源码下载和编译

下载 git clone https://github.com/jquery/jquery.git编译 下载完成后&#xff0c;进入jquery文件夹&#xff0c;运行如下命令&#xff1a; npm run build最后全部编译完成&#xff0c;生成的文件在目录dist文件夹下&#xff1a; 有兴趣的就可以开始研究源码了。

jQuery源码阅读

1. 立即执行函数 简化后的代码就是这样 (function(global, factory) {... })(window, function () {}); Q&#xff1a;采用立即执行函数的好处是什么呢&#xff1f; A: 通过定义一个匿名函数&#xff0c;创建了一个新的函数作用域&#xff0c;相当于创建了一个私有的命名空…

jQuery -- jQuery源码(一):核心功能

一、jQuery无new构建实例 1、$就是jQuery的别称 可以在$和jQuery对象挂在在window中&#xff0c;实现全局引用。 给Windows对象扩展一个$的属性&#xff0c;让它拿到jQuery构造函数的引用 可以用$访问到jQuery的构造函数 // jQuery.js (function(root) {var jQuery functio…

制作一个游戏编辑器玩玩(1)

今天准备着手例用空闲时间制作一个游戏编辑器&#xff0c;一是因为这些年来积累了不少的算法和制作经验&#xff0c;它们是分散的&#xff0c;零乱的&#xff0c;想搞一次规整。二是自己一起想做一个简单点的游戏编辑器&#xff0c;可以让自己的小朋友把自己的想法在上面实现&a…

游戏策划的软件与工具

游戏策划的软件与工具 UXplayer https://www.jianshu.com/p/ceddde705933 gongjutitle.png 本文修改自前公司的一份交接文档&#xff0c;分享了工作中一些常用的软件。 Axure 界面示意图/流程图制作软件 大前提&#xff1a;Windows系统、无法直连外网 Mac系统的话&#xff0c;…

Tiled游戏地图编辑器

下载 软件是免费的,直接官网下载就好了 下载链接:https://www.mapeditor.org/ 新建地图 左上角 >> 文件 >> 创建新地图 快捷键:ctrln 根据你的需求设置地图大小 导入素材新建图块集 左上角 >> 文件 >> 新图块 新建你的图集文件.png 如果你已…

Android游戏开发之地图编辑器的使用以及绘制地图 (四)

雨松MOMO带你走进游戏开发的世界之地图编辑器的使用以及绘制地图 雨松MOMO原创文章如转载&#xff0c;请注明&#xff1a;转载至我的独立域名博客雨松MOMO程序研究院&#xff0c;原文地址:http://www.xuanyusong.com/archives/211 Mappy中文地图编辑器的使用说明下载地址&#…

编辑器

问题描述 你现在要实现一个针对于数字序列的编辑器。 初始的时候&#xff0c;序列是空的。 在之后&#xff0c;有以下五种操作&#xff1a; I x 在光标之后插入x D 删除光标之前的数字 L 将光标向左移动&#xff0c;如果已经在最左&#xff0c;则不移动 R 将光标向右移动&#…

代码编辑器

文章来源&#xff1a;几款非常优秀且常用的代码编辑器 ... VS CodeSource InsightVimUltraEditeclipseUnderstandAtomSublime Text 对于软件开发人员&#xff0c;代码编辑器好用与否直接影响代码编辑的效率。软件开发&#xff0c;基本上都有集成开发环境&#xff08;IDE&#x…

Unity的编辑器

1大部分人Unity编辑器是vistual 2.变量 2.1新建C#文件 鼠标点击Assets-->再点击create-->点击C#Sprite 2.2先用鼠标点击游戏物体(Cube)将c#文件拖拽到Inspector下&#xff0c;双击C#文件可以进入编写代码 2.3变量 public 变量类型 变量; //公有属性在Inspector下可…

游戏编辑器框架

原文&#xff1a;http://www.cnblogs.com/winsonchen/archive/2008/03/29/1128575.html 《游戏创造》08年第二期有一篇关于“&#xff57;xWidget游戏编辑器框架”开发的文章&#xff0c;作者使用过unreal引擎&#xff0c;熟悉unreal编辑器实现细节。该作者建议采用wWidget开发…

RPG++——游戏编辑器的开发

完整资料进入【数字空间】查看——baidu搜索"writebug" 随着当下电子设备的普及以及人们对娱乐需求的上升&#xff0c;电子游戏逐渐走进千家万户。RPG&#xff08;角色扮演&#xff09;游戏作为最经典的游戏种类之一&#xff0c;因其游戏形式多样&#xff0c;自由度…