欢迎光临
我们一直在努力

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

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 的核心思路不是简单模糊,而是在平滑时尽量保持“颜色差异大、梯度变化大”的边缘不被抹掉。

    官方注释说明了几个关键点:

  • src 必须是 8 位 3 通道图像。
  • dst 的大小和类型与 src 保持一致。
  • flags 可以选择 RecursFilter 或 NormconvFilter。
  • sigmaS 控制空间范围。
  • sigmaR 控制颜色或亮度差异的容忍程度。
  • 如果你把它和普通模糊相比,就会发现普通模糊更容易把边界也一起糊掉,而这个函数会更努力地把轮廓留住。

    5. 参数含义解析

    参数名类型必填含义
    src InputArray 输入彩色图像
    dst OutputArray 输出图像
    flags EdgePreservingMethods 边缘保留实现模式
    sigmaS float 空间邻域范围
    sigmaR float 颜色/亮度差异容忍度

    补充说明:

  • sigmaS 越大,影响范围通常越宽。
  • sigmaR 越大,更多差异会被当成“可以一起平滑”的邻域。
  • RecursFilter 是默认模式,适合先建立直觉。
  • NormconvFilter 适合和默认模式一起比较理解。
  • 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. 注意事项

  • 输入必须是 8 位 3 通道图像。
  • 结果图会保持和原图相同的尺寸与类型。
  • sigmaR 过大时,边缘保护效果会变弱。
  • 纹理越丰富,滤镜效果越容易看出来。
  • 9. 调优建议

  • 先用默认值看结果,再逐步调整 sigmaS 和 sigmaR。
  • 如果纹理没有被充分削弱,可以适当增大 sigmaS。
  • 如果边缘开始变糊,可以尝试减小 sigmaR。
  • 教学时最好使用边界清晰、纹理明显的合成图。
  • 10. 进阶扩展

  • 可以把它和 DetailEnhance 放在一起理解“先平滑,再增强细节”的流程。
  • 可以把结果作为风格化或漫画化的前处理。
  • 可以尝试不同 flags 对真实照片和合成图的差异。
  • 可以结合区域分割做局部边缘保留处理。
  • 11. 常见错误排查

  • 把灰度图传给 EdgePreservingFilter。
  • 把它误认为普通高斯模糊。
  • 忘记比较两种 flags,导致教学重点不清楚。
  • sigmaR 设置过大,结果变得过于平滑。
  • 相关链接:

    • WPF 教学控件:Cv2EdgePreservingFilterControl.xaml.cs
    • 样例实现:EdgePreservingFilterSample.cs
    • 官方文档源码位置:OpenCvSharp/Cv2/Cv2_photo.cs
    赞(0)
    未经允许不得转载:171主机测评 » OpencvSharp 算子学习教案之 - Cv2.EdgePreservingFilter
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址