bilareralFilter双边滤波函数

本文详细介绍了OpenCV中bilateralFilter函数的使用及其原理,包括参数解释、高斯相似度权值和距离权值的计算。源码分析展示了双边滤波对图像的处理过程,以及在不同参数设置下对图像效果的影响。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

C++: void **bilateralFilte**r(InputArray src, OutputArray dst, int d, double sigmaColor, double sigmaSpace, int borderType=BORDER_DEFAULT )¶ 
表示对图像进行双边滤波,它能很好地对图像进行滤波,去除噪声的能力很好,并且增强边缘,但是运行慢相对于其他的滤波器 
参数的详解: 
src:表示输入的图像 
OutputArray dst:表示输出的图像 
int类型的d,表示在过滤过程中每个像素邻域的直径。如果这个值我们设其为非正数,那么OpenCV会从第五个参数sigmaSpace来计算出它来。 
double类型的sigmaColor,颜色空间滤波器的sigma值。这个参数的值越大,就表明该像素邻域内有更宽广的颜色会被混合到一起,产生较大的半相等颜色区域。 
double类型的sigmaSpace坐标空间中滤波器的sigma值,坐标空间的标注方差。他的数值越大,意味着越远的像素会相互影响,从而使更大的区域足够相似的颜色获取相同的颜色。当d>0,d指定了邻域大小且与sigmaSpace无关。否则,d正比于sigmaSpace。 
int类型的borderType,用于推断图像外部像素的某种边界模式。注意它有默认值BORDER_DEFAULT。

简单地说它是以被处理像素与其周围像素的距离作为权重而进行的一种加权平均过程。 
高斯距离权值为: 
这里写图片描述

其中,d(ξ,x)=d(ξ-x)=||ξ-x||表示的是两个像素ξ和x之间的距离。 
但该权值仅仅考虑的是距离,而对像素本身的亮度信息没有考虑,因此高斯滤波的结果是使整幅图像都模糊了,即图像的边缘信息(高频部分)被严重削弱了。我们知道当图像中邻域像素亮度与被处理像素的亮度差异很大时,邻域像素与该像素的关系很小的,即两者相似性很差。因此双边滤波还考虑了领域像素的亮度信息,通过计算相似度来赋予领域像素一定的权重,下面就是高斯相似度的权值:

这里写图片描述

其中,σ(f(ξ),f(x))=||f(ξ)-f(x)||表示两个像素亮度之差。最终的双边滤波的公式为:

这里写图片描述

其中,这里写图片描述,Σ表示的是邻域范围,及滤波内核大小,f(ξ)表示原图。

代码详解:

<ol start="1" class="dp-cpp" style="padding: 0px; border: none; color: rgb(92, 92, 92); font-family: Consolas, 'Courier New', Courier, mono, serif; font-size: 12px; line-height: 26px; margin: 0px 0px 1px 45px !important;"><li class="alt" style="border-style: none none none solid; border-left-width: 3px; border-left-color: rgb(108, 226, 108); list-style: decimal-leading-zero outside; color: inherit; line-height: 18px; margin: 0px !important; padding: 0px 3px 0px 10px !important;"><span style="margin: 0px; padding: 0px; border: none; color: black; background-color: inherit;"><span class="keyword" style="margin: 0px; padding: 0px; border: none; color: rgb(0, 102, 153); font-weight: bold; background-color: inherit;">void</span><span style="margin: 0px; padding: 0px; border: none; background-color: inherit;"> cv::adaptiveBilateralFilter( InputArray _src, OutputArray _dst, Size ksize,  </span></span></li><li style="border-style: none none none solid; border-left-width: 3px; border-left-color: rgb(108, 226, 108); list-style: decimal-leading-zero outside; line-height: 18px; margin: 0px !important; padding: 0px 3px 0px 10px !important; background-color: rgb(248, 248, 248);"><span style="margin: 0px; padding: 0px; border: none; color: black; background-color: inherit;">                                  <span class="datatypes" style="margin: 0px; padding: 0px; border: none; color: rgb(46, 139, 87); font-weight: bold; background-color: inherit;">double</span><span style="margin: 0px; padding: 0px; border: none; background-color: inherit;"> sigmaSpace, </span><span class="datatypes" style="margin: 0px; padding: 0px; border: none; color: rgb(46, 139, 87); font-weight: bold; background-color: inherit;">double</span><span style="margin: 0px; padding: 0px; border: none; background-color: inherit;"> maxSigmaColor, Point anchor, </span><span class="datatypes" style="margin: 0px; padding: 0px; border: none; color: rgb(46, 139, 87); font-weight: bold; background-color: inherit;">int</span><span style="margin: 0px; padding: 0px; border: none; background-color: inherit;"> borderType )  </span></span></li><li class="alt" style="border-style: none none none solid; border-left-width: 3px; border-left-color: rgb(108, 226, 108); list-style: decimal-leading-zero outside; color: inherit; line-height: 18px; margin: 0px !important; padding: 0px 3px 0px 10px !important;"><span style="margin: 0px; padding: 0px; border: none; color: black; background-color: inherit;">{  </span></li><li style="border-style: none none none solid; border-left-width: 3px; border-left-color: rgb(108, 226, 108); list-style: decimal-leading-zero outside; line-height: 18px; margin: 0px !important; padding: 0px 3px 0px 10px !important; background-color: rgb(248, 248, 248);"><span style="margin: 0px; padding: 0px; border: none; color: black; background-color: inherit;">    <span class="comment" style="margin: 0px; padding: 0px; border: none; color: rgb(0, 130, 0); background-color: inherit;">//得到输入图像矩阵和与其尺寸类型一致的输出图像矩阵</span><span style="margin: 0px; padding: 0px; border: none; background-color: inherit;">  </span></span></li><li class="alt" style="border-style: none none none solid; border-left-width: 3px; border-left-color: rgb(108, 226, 108); list-style: decimal-leading-zero outside; color: inherit; line-height: 18px; margin: 0px !important; padding: 0px 3px 0px 10px !important;"><span style="margin: 0px; padding: 0px; border: none; color: black; background-color: inherit;">    Mat src = _src.getMat();  </span></li><li style="border-style: none none none solid; border-left-width: 3px; border-left-color: rgb(108, 226, 108); list-style: decimal-leading-zero outside; line-height: 18px; margin: 0px !important; padding: 0px 3px 0px 10px !important; background-color: rgb(248, 248, 248);"><span style="margin: 0px; padding: 0px; border: none; color: black; background-color: inherit;">    _dst.create(src.size(), src.type());  </span></li><li class="alt" style="border-style: none none none solid; border-left-width: 3px; border-left-color: rgb(108, 226, 108); list-style: decimal-leading-zero outside; color: inherit; line-height: 18px; margin: 0px !important; padding: 0px 3px 0px 10px !important;"><span style="margin: 0px; padding: 0px; border: none; color: black; background-color: inherit;">    Mat dst = _dst.getMat();  </span></li><li style="border-style: none none none solid; border-left-width: 3px; border-left-color: rgb(108, 226, 108); list-style: decimal-leading-zero outside; line-height: 18px; margin: 0px !important; padding: 0px 3px 0px 10px !important; background-color: rgb(248, 248, 248);"><span style="margin: 0px; padding: 0px; border: none; color: black; background-color: inherit;">    <span class="comment" style="margin: 0px; padding: 0px; border: none; color: rgb(0, 130, 0); background-color: inherit;">//该算法只能处理8位二进制的灰度图像和三通道的彩色图像</span><span style="margin: 0px; padding: 0px; border: none; background-color: inherit;">  </span></span></li><li class="alt" style="border-style: none none none solid; border-left-width: 3px; border-left-color: rgb(108, 226, 108); list-style: decimal-leading-zero outside; color: inherit; line-height: 18px; margin: 0px !important; padding: 0px 3px 0px 10px !important;"><span style="margin: 0px; padding: 0px; border: none; color: black; background-color: inherit;">    CV_Assert(src.type() == CV_8UC1 || src.type() == CV_8UC3);  </span></li><li style="border-style: none none none solid; border-left-width: 3px; border-left-color: rgb(108, 226, 108); list-style: decimal-leading-zero outside; line-height: 18px; margin: 0px !important; padding: 0px 3px 0px 10px !important; background-color: rgb(248, 248, 248);"><span style="margin: 0px; padding: 0px; border: none; color: black; background-color: inherit;">    <span class="comment" style="margin: 0px; padding: 0px; border: none; color: rgb(0, 130, 0); background-color: inherit;">//得到滤波内核的锚点</span><span style="margin: 0px; padding: 0px; border: none; background-color: inherit;">  </span></span></li><li class="alt" style="border-style: none none none solid; border-left-width: 3px; border-left-color: rgb(108, 226, 108); list-style: decimal-leading-zero outside; color: inherit; line-height: 18px; margin: 0px !important; padding: 0px 3px 0px 10px !important;"><span style="margin: 0px; padding: 0px; border: none; color: black; background-color: inherit;">    anchor = normalizeAnchor(anchor,ksize);  </span></li><li style="border-style: none none none solid; border-left-width: 3px; border-left-color: rgb(108, 226, 108); list-style: decimal-leading-zero outside; line-height: 18px; margin: 0px !important; padding: 0px 3px 0px 10px !important; background-color: rgb(248, 248, 248);"><span style="margin: 0px; padding: 0px; border: none; color: black; background-color: inherit;">    <span class="keyword" style="margin: 0px; padding: 0px; border: none; color: rgb(0, 102, 153); font-weight: bold; background-color: inherit;">if</span><span style="margin: 0px; padding: 0px; border: none; background-color: inherit;">( src.depth() == CV_8U )  </span></span></li><li class="alt" style="border-style: none none none solid; border-left-width: 3px; border-left-color: rgb(108, 226, 108); list-style: decimal-leading-zero outside; color: inherit; line-height: 18px; margin: 0px !important; padding: 0px 3px 0px 10px !important;"><span style="margin: 0px; padding: 0px; border: none; color: black; background-color: inherit;">        adaptiveBilateralFilter_8u( src, dst, ksize, sigmaSpace, maxSigmaColor, anchor, borderType );  </span></li><li style="border-style: none none none solid; border-left-width: 3px; border-left-color: rgb(108, 226, 108); list-style: decimal-leading-zero outside; line-height: 18px; margin: 0px !important; padding: 0px 3px 0px 10px !important; background-color: rgb(248, 248, 248);"><span style="margin: 0px; padding: 0px; border: none; color: black; background-color: inherit;">    <span class="keyword" style="margin: 0px; padding: 0px; border: none; color: rgb(0, 102, 153); font-weight: bold; background-color: inherit;">else</span><span style="margin: 0px; padding: 0px; border: none; background-color: inherit;">  </span></span></li><li class="alt" style="border-style: none none none solid; border-left-width: 3px; border-left-color: rgb(108, 226, 108); list-style: decimal-leading-zero outside; color: inherit; line-height: 18px; margin: 0px !important; padding: 0px 3px 0px 10px !important;"><span style="margin: 0px; padding: 0px; border: none; color: black; background-color: inherit;">        CV_Error( CV_StsUnsupportedFormat,  </span></li><li style="border-style: none none none solid; border-left-width: 3px; border-left-color: rgb(108, 226, 108); list-style: decimal-leading-zero outside; line-height: 18px; margin: 0px !important; padding: 0px 3px 0px 10px !important; background-color: rgb(248, 248, 248);"><span style="margin: 0px; padding: 0px; border: none; color: black; background-color: inherit;">        <span class="string" style="margin: 0px; padding: 0px; border: none; color: blue; background-color: inherit;">"Adaptive Bilateral filtering is only implemented for 8u images"</span><span style="margin: 0px; padding: 0px; border: none; background-color: inherit;"> );  </span></span></li><li class="alt" style="border-style: none none none solid; border-left-width: 3px; border-left-color: rgb(108, 226, 108); list-style: decimal-leading-zero outside; color: inherit; line-height: 18px; margin: 0px !important; padding: 0px 3px 0px 10px !important;"><span style="margin: 0px; padding: 0px; border: none; color: black; background-color: inherit;">}  </span></li></ol>
在这里我们以处理 8 为二进制图像为例,因此它调用了 bilateralFilter_8u 函数:

  1. static void  
  2. bilateralFilter_8u( const Mat& src, Mat& dst, int d,  
  3.     double sigma_color, double sigma_space,  
  4.     int borderType )  
  5. {  
  6.   
  7.     int cn = src.channels();        //得到图像的通道数,即是灰度图像还是彩色图像  
  8.     int i, j, maxk, radius;  
  9.     Size size = src.size();         //得到图像的大小尺寸  
  10.     //处理之前再次检查图像中的相关信息是否正确  
  11.     CV_Assert( (src.type() == CV_8UC1 || src.type() == CV_8UC3) &&  
  12.               src.type() == dst.type() && src.size() == dst.size() &&  
  13.          &n
### 关于双边滤波函数的实现与介绍 #### 双边滤波的核心概念 双边滤波是一种非线性滤波技术,它通过结合空间距离和像素强度差异来计算权重矩阵。这种方法能够在平滑图像的同时有效保留边缘信息[^2]。 #### MATLAB中的双边滤波实现 以下是基于MATLAB的一个简单双边滤波函数实现方式: ```matlab function filteredImage = bilateralFilter(image, d, sigmaColor, sigmaSpace) % image: 输入图像 (灰度图或彩色图) % d: 邻域直径 % sigmaColor: 值域标准差 % sigmaSpace: 空间标准差 [rows, cols, ~] = size(image); filteredImage = zeros(size(image), class(image)); for i = 1:rows for j = 1:cols pixelValue = double(image(i,j,:)); % 当前像素值 weightSum = 0; valueSum = 0; for m = max(1,i-d):min(rows,i+d) for n = max(1,j-d):min(cols,j+d) neighborPixel = double(image(m,n,:)); % 邻域像素值 spatialDistance = exp(-((i-m)^2 + (j-n)^2) / (2*sigmaSpace^2)); % 空间权重 intensityDifference = exp(-sum((pixelValue - neighborPixel).^2) / (2*sigmaColor^2)); % 强度权重 totalWeight = spatialDistance * intensityDifference; % 总权重 valueSum = valueSum + totalWeight * neighborPixel; % 加权求和 weightSum = weightSum + totalWeight; % 权重总和 end end filteredImage(i,j,:) = uint8(valueSum ./ weightSum); % 归一化并赋值给输出图像 end end end ``` 上述代码实现了基本的双边滤波功能,其中`d`表示邻域大小,`sigmaColor`控制颜色相似性的影响程度,`sigmaSpace`则决定空间位置的影响范围[^3]。 #### OpenCV中的双边滤波应用 在OpenCV库中,可以通过调用`bilateralFilter()`函数快速完成双边滤波操作。其语法如下所示: ```cpp void bilateralFilter(InputArray src, OutputArray dst, int d, double sigmaColor, double sigmaSpace, int borderType=BORDER_DEFAULT ); ``` - `src`: 输入图像。 - `dst`: 输出图像。 - `d`: 如果该参数大于零,则定义了相邻像素的距离;如果等于负数,则从`sigmaSpace`推导得出。 - `sigmaColor`: 控制亮度/颜色变化的标准偏差。 - `sigmaSpace`: 定义坐标空间内的标准偏差。 #### 边缘保护机制分析 相比于传统的高斯模糊,双边滤波增加了对像素值差异敏感的一维高斯分布因子。这使得即使两个像素位于相近的空间位置上,但如果它们的颜色差距较大,也会被赋予较低的权重,从而达到保持边界清晰的效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值