OpencvSharp 算子学习教案之 – Cv2.EdgePreservingFilter
大家好,Opencv在很多工程项目中都会用到,而OpencvSharp则是以C#开发与实现的Opencv操作库,对.NET开发人员友好,但很多API的中文资料、应用场景及常见坑点等缺乏系统性归纳,因此这系列博客将给大家带来Cv2及Mat对象全系列算子学习教案,供大家参考学习。
Cv2.EdgePreservingFilter
- 教案版本:V1.0
- 面向对象:OpenCvSharp 初学者
- 所属模块:photo
- 源码位置:OpenCvSharp/Cv2/Cv2_photo.cs:383
摘要:本页演示 EdgePreservingFilter(InputArray,OutputArray,EdgePreservingMethods,float,float) 如何在保留边缘的同时平滑内部纹理,并对比 RecursFilter 与 NormconvFilter 两种模式;示例使用带有房屋、树叶和织物纹理的合成场景,便于初学者观察边界与纹理的变化。
1. 函数名称(带参数签名)
public static void EdgePreservingFilter(InputArray src, OutputArray dst, EdgePreservingMethods flags = EdgePreservingMethods.RecursFilter, float sigmaS = 60, float sigmaR = 0.4f)
2. 函数用途
Cv2.EdgePreservingFilter(…) 用来在尽量保留边缘和轮廓的前提下,对图像进行平滑处理。
它常用于:
3. 函数公式
可以把它理解成一个边缘感知的平滑映射:
I
′
=
F
e
p
(
I
,
f
l
a
g
,
σ
S
,
σ
R
)
I'=\\mathcal{F}_{ep}(I,flag,\\sigma_S,\\sigma_R)
I′=Fep(I,flag,σS,σR)
其中 I 是输入图像,I' 是输出图像,flag 决定实现模式。
4. 函数原理说明
EdgePreservingFilter 的核心思路不是简单模糊,而是在平滑时尽量保持“颜色差异大、梯度变化大”的边缘不被抹掉。
官方注释说明了几个关键点:
如果你把它和普通模糊相比,就会发现普通模糊更容易把边界也一起糊掉,而这个函数会更努力地把轮廓留住。
5. 参数含义解析
| src | InputArray | 是 | 输入彩色图像 |
| dst | OutputArray | 是 | 输出图像 |
| flags | EdgePreservingMethods | 否 | 边缘保留实现模式 |
| sigmaS | float | 否 | 空间邻域范围 |
| sigmaR | float | 否 | 颜色/亮度差异容忍度 |
补充说明:
6. 应用场景列表
| 场景A:轮廓保留 | 在平滑时尽量保住边界 | 图像预处理 |
| 场景B:纹理削弱 | 弱化衣物、墙面等重复纹理 | 风格化前处理 |
| 场景C:细节整理 | 保留大轮廓、压低高频细节 | 视觉展示 |
| 场景D:教学比较 | 对比两种 flags 的效果差异 | 初学者入门 |
7. 函数使用示例
说明:下面示例先构造一张带房屋、树叶和织物纹理的合成图,再分别使用两种 flags 做边缘保留平滑。
using OpenCvSharp;
internal static class Program
{
private static void Main()
{
// 创建一张适合做边缘保留滤镜演示的合成图,包含平滑区、清晰边缘和重复纹理。
using var source = new Mat(360, 480, MatType.CV_8UC3, new Scalar(236, 238, 242));
// 先铺好天空和草地,让观众容易看到滤镜在大块区域里的平滑效果。
Cv2.Rectangle(source, new Rect(0, 0, 480, 188), new Scalar(248, 241, 226), –1, LineTypes.AntiAlias);
Cv2.Rectangle(source, new Rect(0, 188, 480, 172), new Scalar(212, 231, 195), –1, LineTypes.AntiAlias);
Cv2.Ellipse(source, new Point(180, 192), new Size(170, 48), 0, 0, 360, new Scalar(198, 220, 184), –1, LineTypes.AntiAlias);
// 画太阳和云朵,顺带测试边缘保留时会不会把柔和边界也一起抹掉。
Cv2.Circle(source, new Point(390, 74), 26, new Scalar(64, 215, 255), –1, LineTypes.AntiAlias);
Cv2.Circle(source, new Point(114, 58), 24, new Scalar(255, 255, 255), –1, LineTypes.AntiAlias);
Cv2.Circle(source, new Point(338, 52), 20, new Scalar(255, 255, 255), –1, LineTypes.AntiAlias);
// 房子区域包含窗格和屋顶边线,适合观察结构是否仍然清楚。
Cv2.Rectangle(source, new Rect(62, 150, 124, 88), new Scalar(229, 212, 191), –1, LineTypes.AntiAlias);
var roof = new[]
{
new Point(50, 152),
new Point(124, 104),
new Point(198, 152),
};
Cv2.FillConvexPoly(source, roof, new Scalar(118, 92, 74), LineTypes.AntiAlias);
Cv2.Rectangle(source, new Rect(78, 172, 24, 22), new Scalar(255, 245, 232), –1, LineTypes.AntiAlias);
Cv2.Rectangle(source, new Rect(132, 172, 24, 22), new Scalar(255, 245, 232), –1, LineTypes.AntiAlias);
Cv2.Rectangle(source, new Rect(96, 186, 34, 52), new Scalar(158, 128, 95), –1, LineTypes.AntiAlias);
// 树叶使用大量小圆点制造高频细节,便于观察滤波是否会弱化纹理。
Cv2.Rectangle(source, new Rect(330, 164, 28, 86), new Scalar(96, 73, 54), –1, LineTypes.AntiAlias);
foreach (var center in new[] { new Point(304, 138), new Point(328, 122), new Point(356, 114), new Point(380, 126) })
{
Cv2.Circle(source, center, 22, new Scalar(86, 164, 92), –1, LineTypes.AntiAlias);
Cv2.Circle(source, new Point(center.X + 4, center.Y – 4), 12, new Scalar(104, 184, 112), –1, LineTypes.AntiAlias);
}
// 织物纹理是最容易看出“保边缘、削弱纹理”差异的区域。
var clothRect = new Rect(110, 246, 172, 88);
Cv2.Rectangle(source, clothRect, new Scalar(162, 134, 100), –1, LineTypes.AntiAlias);
for (var offset = –clothRect.Height; offset < clothRect.Width; offset += 14)
{
var start = new Point(clothRect.Left + offset, clothRect.Bottom);
var end = new Point(clothRect.Left + offset + clothRect.Height, clothRect.Top);
Cv2.Line(source, start, end, new Scalar(210, 206, 190), 2, LineTypes.AntiAlias);
}
// 准备两份输出,分别对应两种边缘保留模式。
using var recursResult = new Mat();
using var normconvResult = new Mat();
Cv2.EdgePreservingFilter(source, recursResult, EdgePreservingMethods.RecursFilter, 60, 0.4f);
Cv2.EdgePreservingFilter(source, normconvResult, EdgePreservingMethods.NormconvFilter, 60, 0.4f);
Cv2.ImWrite("edge-preserving-recurs.png", recursResult);
Cv2.ImWrite("edge-preserving-normconv.png", normconvResult);
}
}
8. 注意事项
9. 调优建议
10. 进阶扩展
11. 常见错误排查
相关链接:
- WPF 教学控件:Cv2EdgePreservingFilterControl.xaml.cs
- 样例实现:EdgePreservingFilterSample.cs
- 官方文档源码位置:OpenCvSharp/Cv2/Cv2_photo.cs



