news 2026/5/12 10:30:55

OpencvSharp 算子学习教案之 - Cv2.BilateralFilter

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
OpencvSharp 算子学习教案之 - Cv2.BilateralFilter

OpencvSharp 算子学习教案之 - Cv2.BilateralFilter

大家好,Opencv在很多工程项目中都会用到,而OpencvSharp则是以C#开发与实现的Opencv操作库,对.NET开发人员友好,但很多API的中文资料、应用场景及常见坑点等缺乏系统性归纳,因此这系列博客将给大家带来Cv2及Mat对象全系列算子学习教案,供大家参考学习。

Cv2.BilateralFilter

  • 教案版本:V1.0
  • 面向对象:OpenCvSharp 初学者
  • 所属模块:imgproc
  • 源码位置:OpenCvSharp/Cv2/Cv2_imgproc.cs:191

摘要:BilateralFilter 是保边缘滤波,sigmaColor 和 sigmaSpace 分别控制颜色与空间的影响范围。本文用轻度、中等和自动直径三组参数,帮助初学者看懂它为什么比普通模糊更适合保边缘去噪。

1. 函数名称(带参数签名)

publicstaticvoidBilateralFilter(InputArraysrc,OutputArraydst,intd,doublesigmaColor,doublesigmaSpace,BorderTypesborderType=BorderTypes.Default)

2. 函数用途

Cv2.BilateralFilter的作用,是在尽量保住边缘的前提下平滑图像。

这个函数最常见的用途有:

  1. 去噪但尽量不糊边。
  2. 让照片看起来更干净,同时保留轮廓。
  3. 做卡通化或边缘友好的预处理。
  4. 帮助理解“空间距离”和“颜色相似度”如何共同决定权重。

它比 GaussianBlur 更复杂,也比普通平均滤波更适合保边缘。

3. 函数公式

双边滤波可以理解成带两个权重的加权平均:

dst(p)=1Wp∑q∈ΩI(q)exp⁡(−∥p−q∥22σs2)exp⁡(−∥I(p)−I(q)∥22σc2) dst(p) = \frac{1}{W_p} \sum_{q \in \Omega} I(q) \exp\left(-\frac{\|p-q\|^2}{2\sigma_s^2}\right) \exp\left(-\frac{\|I(p)-I(q)\|^2}{2\sigma_c^2}\right)dst(p)=Wp1qΩI(q)exp(2σs2pq2)exp(2σc2I(p)I(q)2)

其中空间权重由sigmaSpace控制,颜色权重由sigmaColor控制,WpW_pWp是归一化系数。

4. 函数原理说明

这个函数会同时考虑两个条件:

  1. 两个像素是不是离得近。
  2. 两个像素的颜色是不是相近。

如果两个像素距离很远,或者颜色差得很大,它们的影响就会被明显削弱。

  1. d决定邻域直径。
  2. sigmaColor决定颜色相近程度的容忍度。
  3. sigmaSpace决定空间相近程度的容忍度。
  4. d <= 0时,OpenCV 会根据sigmaSpace推导邻域大小。

5. 参数含义解析

参数名类型必填含义
srcInputArray输入图像
dstOutputArray输出图像
dint邻域直径,非正数时会自动推导
sigmaColordouble颜色空间中的标准差
sigmaSpacedouble坐标空间中的标准差
borderTypeBorderTypes边界外推方式

补充说明:

  1. 官方文档说明它不支持 in-place。
  2. 输入图像一般要求是 8 位或浮点图像。
  3. 常见输入是 1 通道或 3 通道图像。
  4. BORDER_WRAP不支持。

6. 应用场景列表

场景名场景说明典型用途
场景A:保边缘去噪降噪同时保轮廓照片处理
场景B:卡通化预处理平滑色块但保边缘风格化
场景C:人像优化抑制皮肤噪点美颜预处理
场景D:参数教学对比 d 和 sigma 的作用初学者理解权重

7. 函数使用示例

下面的 Console 程序演示Cv2.BilateralFilter。示例会先给图像加入一点高斯噪声,再分别用轻度、中等和自动直径三组参数做对比。

usingSystem;usingSystem.Text;usingOpenCvSharp;internalstaticclassProgram{privatestaticvoidMain(){// 控制台输出切换到 UTF-8,避免中文说明乱码。Console.OutputEncoding=Encoding.UTF8;// 运行完整演示,观察双边滤波如何在保边缘的同时去噪。RunDemo();}/// <summary>/// 演示双边滤波的输出特点。/// </summary>privatestaticvoidRunDemo(){usingvarcleanSource=CreateDemoImage();usingvarnoisySource=AddGaussianNoise(cleanSource,20.0,2026);usingvargentle=newMat();usingvarmedium=newMat();usingvarstrong=newMat();// 这里准备三组参数,分别代表轻度、中等和自动直径三种教学写法。Cv2.BilateralFilter(noisySource,gentle,5,35.0,35.0,BorderTypes.Default);Cv2.BilateralFilter(noisySource,medium,9,60.0,60.0,BorderTypes.Default);Cv2.BilateralFilter(noisySource,strong,0,90.0,90.0,BorderTypes.Default);Console.WriteLine("场景A:BilateralFilter(InputArray src, OutputArray dst, int d, double sigmaColor, double sigmaSpace, BorderTypes borderType = BorderTypes.Default)");Console.WriteLine("BilateralFilter 会同时考虑空间距离和颜色差异,因此比普通模糊更能保住边缘。\n");Console.WriteLine($"带噪声图像:{DescribeMat(noisySource)}");Console.WriteLine();PrintCase("轻度双边滤波",noisySource,gentle,"d=5, sigmaColor=35, sigmaSpace=35","参数较小时,去噪比较温和,边缘也更容易保留。");PrintCase("中等双边滤波",noisySource,medium,"d=9, sigmaColor=60, sigmaSpace=60","这个参数组合会带来更明显的平滑,但仍比普通模糊更保边缘。");PrintCase("自动直径",noisySource,strong,"d=0, sigmaColor=90, sigmaSpace=90","d=0 时,OpenCV 会根据 sigmaSpace 推导邻域直径。");Console.WriteLine("教学结论:sigmaColor 控制颜色相似度,sigmaSpace 控制空间邻域,d 决定或推导邻域直径。\n");}/// <summary>/// 创建一张用于教学的源图。/// </summary>privatestaticMatCreateDemoImage(){// 使用一张人像风格的教学图,便于观察边缘是否被保留。varcanvas=newMat(400,400,MatType.CV_8UC3,newScalar(245,238,234));Cv2.Ellipse(canvas,newPoint(200,170),newSize(118,140),0,0,360,newScalar(35,25,20),-1,LineTypes.AntiAlias);Cv2.Ellipse(canvas,newPoint(200,182),newSize(78,96),0,0,360,newScalar(122,182,228),-1,LineTypes.AntiAlias);Cv2.Ellipse(canvas,newPoint(200,332),newSize(148,72),0,0,360,newScalar(165,100,58),-1,LineTypes.AntiAlias);Cv2.PutText(canvas,"BilateralFilter",newPoint(24,374),HersheyFonts.HersheySimplex,0.8,newScalar(55,40,35),2,LineTypes.AntiAlias);returncanvas;}/// <summary>/// 给图像叠加高斯噪声。/// </summary>privatestaticMatAddGaussianNoise(Matsource,doublesigma,intseed){varrng=newRandom(seed);varresult=source.Clone();for(varrow=0;row<result.Rows;row++){for(varcol=0;col<result.Cols;col++){varpixel=source.At<Vec3b>(row,col);result.At<Vec3b>(row,col)=newVec3b(ClampToByte(pixel.Item0+NextGaussian(rng)*sigma),ClampToByte(pixel.Item1+NextGaussian(rng)*sigma),ClampToByte(pixel.Item2+NextGaussian(rng)*sigma));}}returnresult;}/// <summary>/// 打印一个对比场景。/// </summary>privatestaticvoidPrintCase(stringlabel,Matsource,Matresult,stringtitle,stringcomment){usingvardiff=newMat();Cv2.Absdiff(source,result,diff);Console.WriteLine($"[{label}]{title}");Console.WriteLine(comment);Console.WriteLine($"结果:{DescribeMat(result)}");Console.WriteLine($"与源图的灰度差值统计:{DescribeGrayStatistics(diff)}");Console.WriteLine();}/// <summary>/// 描述 Mat 的核心信息。/// </summary>privatestaticstringDescribeMat(Matmat){return$"Size={mat.Width}x{mat.Height}, Channels={mat.Channels()}, Type={mat.Type()}, Depth={mat.Depth()}";}/// <summary>/// 计算灰度图的基本统计信息。/// </summary>privatestaticstringDescribeGrayStatistics(Matimage){usingvargray=newMat();Cv2.CvtColor(image,gray,ColorConversionCodes.BGR2GRAY);Cv2.MeanStdDev(gray,outvarmean,outvarstddev);Cv2.MinMaxLoc(gray,outdoubleminVal,outdoublemaxVal);return$"灰度均值={mean.Val0:F2}, 灰度标准差={stddev.Val0:F2}, 最小值={minVal:F0}, 最大值={maxVal:F0}";}/// <summary>/// 生成高斯噪声。/// </summary>privatestaticdoubleNextGaussian(Randomrng){varu1=1.0-rng.NextDouble();varu2=1.0-rng.NextDouble();returnMath.Sqrt(-2.0*Math.Log(u1))*Math.Cos(2.0*Math.PI*u2);}/// <summary>/// 把浮点值夹紧到 8 位像素范围。/// </summary>privatestaticbyteClampToByte(doublevalue){varclamped=Math.Clamp((int)Math.Round(value),byte.MinValue,byte.MaxValue);return(byte)clamped;}}

8. 注意事项

  1. d为非正数时,OpenCV 会根据sigmaSpace推导邻域直径。
  2. 输入图像一般要求是 8 位或浮点图像。
  3. BilateralFilter不支持 in-place。
  4. BORDER_WRAP不支持。

9. 调优建议

  1. 想保边缘,就不要把 sigma 一下子设得太大。
  2. 想要更强的去噪,可以逐步增大sigmaColorsigmaSpace
  3. d=0适合用来演示自动直径推导。
  4. 如果图像已经很干净,双边滤波可能会显得偏慢。

10. 运行说明

  1. 如果你在控制台工程里运行本文示例,直接把代码放进Program.cs即可。
  2. 如果你在本仓库里学习,请打开 WPF 控件Cv2.BilateralFilter,点击“运行场景A”后查看右侧文本框和预览图。
  3. WPF 示例会把轻度、中等和自动直径三种双边滤波结果放在一起对比。

11. 常见错误排查

  1. 把双边滤波当成普通均值滤波使用。
  2. 误以为d=0不会做任何处理,其实它会触发自动推导。
  3. 没有意识到 sigmaColor 和 sigmaSpace 的含义不同。
  4. 忘记它通常比 GaussianBlur 更慢。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/12 10:30:54

边缘AI医疗影像:不确定性量化如何让AI决策更可信

1. 项目概述与核心价值最近在整理一些关于边缘AI在医疗影像中应用的资料&#xff0c;恰好翻到了NXP在2020年发布的一篇关于将AI可解释性技术应用于COVID-19 X光筛查系统的研究。这篇报道虽然发布得比较早&#xff0c;但里面讨论的核心问题——如何让“黑盒”AI在关键时刻变得可…

作者头像 李华
网站建设 2026/5/12 10:30:36

你的数字记忆会消失吗?3步永久保存微信聊天记录

你的数字记忆会消失吗&#xff1f;3步永久保存微信聊天记录 【免费下载链接】WeChatMsg 提取微信聊天记录&#xff0c;将其导出成HTML、Word、CSV文档永久保存&#xff0c;对聊天记录进行分析生成年度聊天报告 项目地址: https://gitcode.com/GitHub_Trending/we/WeChatMsg …

作者头像 李华
网站建设 2026/5/12 10:29:56

2026微欧计品牌深度评测:技术革新与市场格局白皮书

摘要 本白皮书旨在对2026年全球微欧计市场进行一次深度评测&#xff0c;聚焦于各品牌在技术创新、性能表现、应用场景适应性及用户口碑方面的综合实力。微欧计&#xff0c;作为电气设备接触电阻精准测量的核心工具&#xff0c;其技术水平直接关乎电力、轨道交通、工业制造等关…

作者头像 李华
网站建设 2026/5/12 10:29:54

如何彻底告别网盘限速:9大平台直链解析工具完整指南

如何彻底告别网盘限速&#xff1a;9大平台直链解析工具完整指南 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 &#xff0c;支持 百度网盘 / 阿里云盘 / 中国移动云盘 / 天翼云…

作者头像 李华
网站建设 2026/5/12 10:28:19

WindowResizer:Windows窗口强制调整的终极免费指南

WindowResizer&#xff1a;Windows窗口强制调整的终极免费指南 【免费下载链接】WindowResizer 一个可以强制调整应用程序窗口大小的工具 项目地址: https://gitcode.com/gh_mirrors/wi/WindowResizer 还在为那些无法调整大小的应用程序窗口而烦恼吗&#xff1f;WindowR…

作者头像 李华
网站建设 2026/5/12 10:24:35

从零到一:使用DaVinci Developer进行AUTOSAR SWC设计与ECU集成

1. 认识AUTOSAR与DaVinci Developer工具 第一次接触汽车电子开发的朋友&#xff0c;可能会被AUTOSAR这个术语吓到。其实它就像汽车软件界的"普通话"——各家厂商用统一的标准交流&#xff0c;避免出现"鸡同鸭讲"的情况。而DaVinci Developer就是Vector公司…

作者头像 李华