当前位置: 首页 > news >正文

OpencvSharp 算子学习教案之 - Cv2.DrawContours 重载1

OpencvSharp 算子学习教案之 - Cv2.DrawContours 重载1

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

Cv2.DrawContours

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

摘要:本页演示 DrawContours(InputOutputArray, IEnumerable<IEnumerable>, int, Scalar, int, LineTypes, IEnumerable?, int, Point?) 如何按轮廓层级绘制指定子树,并说明 contourIdx 和 maxLevel 的配合方式。

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

publicstaticvoidDrawContours(InputOutputArrayimage,IEnumerable<IEnumerable<Point>>contours,intcontourIdx,Scalarcolor,intthickness=1,LineTypeslineType=LineTypes.Link8,IEnumerable<HierarchyIndex>?hierarchy=null,intmaxLevel=int.MaxValue,Point?offset=null)

2. 函数用途

Cv2.DrawContours(...)用来在图像上绘制一个或多个轮廓的边界,或者在thickness < 0时直接填充轮廓区域。这个重载直接接收点集和层级信息,最适合从“轮廓树”角度理解绘制范围。

它常用于:

  1. 轮廓可视化。
  2. 目标分组和子轮廓高亮。
  3. 带孔区域的边界说明。
  4. 从 FindContours 的结果里筛选某个轮廓子树。

3. 函数公式

如果把轮廓看成有父子关系的树,那么绘制范围可以理解成:

S ( contourIdx , maxLevel ) = { c ∣ c ∈ subtree ( contourIdx ) , depth ( c ) ≤ maxLevel } S(\text{contourIdx},\text{maxLevel})=\{c\mid c\in \text{subtree}(\text{contourIdx}),\;\text{depth}(c)\le \text{maxLevel}\}S(contourIdx,maxLevel)={ccsubtree(contourIdx),depth(c)maxLevel}

这个公式不是 OpenCV 的源码公式,而是帮助初学者理解contourIdxmaxLevel的抽象方式。contourIdx负责选根,maxLevel负责决定向下展开多少层。

4. 函数原理说明

这个函数会先读取轮廓集合,再根据contourIdx选择从哪一个轮廓开始绘制。如果传入了层级信息,maxLevel就会决定要不要继续画子轮廓、孙轮廓。

OpenCV 官方文档明确说明:

  1. thickness >= 0时绘制轮廓边界。
  2. thickness < 0时填充轮廓内部。
  3. maxLevel只在存在层级信息时才有意义。
  4. offset会把所有绘制出来的轮廓一起平移。

对初学者来说,最重要的是理解:DrawContours不是简单地“把数组画出来”,它会根据层级关系决定究竟画哪一部分。

5. 参数含义解析

参数名类型必填含义
imageInputOutputArray要被绘制的图像
contoursIEnumerable<IEnumerable>每条轮廓的点集
contourIdxint要从哪条轮廓开始绘制,负数表示全部绘制
colorScalar轮廓颜色
thicknessint线宽,负数表示填充
lineTypeLineTypes线型,默认Link8
hierarchyIEnumerable?轮廓层级信息
maxLevelint最大绘制层级,默认int.MaxValue
offsetPoint?所有轮廓的整体平移量

补充说明:

  1. hierarchy的每一项都对应一条轮廓。
  2. contourIdx=0并不代表“全部轮廓”,它只代表从第 1 条轮廓开始。
  3. maxLevel越大,递归展开得越深。

6. 应用场景列表

场景名场景说明典型用途
场景A:轮廓树可视化只画一个轮廓及其子树层级教学
场景B:孔洞轮廓看外轮廓和内轮廓的关系掩膜处理
场景C:局部高亮只强调某个目标轮廓调试展示
场景D:结果标注给提取结果加颜色视觉分析

7. 函数使用示例

说明:下面示例对应 WPF 场景 A。它用点集和层级信息绘制轮廓子树,并展示contourIdx=0maxLevel=2的效果。

usingOpenCvSharp;internalstaticclassProgram{privatestaticvoidMain(){// 准备一组有父子关系的轮廓:外轮廓、洞、洞中的小岛,以及右侧独立轮廓。varcontours=new[]{new[]{newPoint(52,50),newPoint(158,40),newPoint(196,98),newPoint(170,174),newPoint(88,186),newPoint(42,122),},new[]{newPoint(88,82),newPoint(138,78),newPoint(154,118),newPoint(126,144),newPoint(82,124),},new[]{newPoint(108,98),newPoint(126,94),newPoint(132,114),newPoint(112,122),},new[]{newPoint(244,62),newPoint(312,46),newPoint(346,94),newPoint(328,156),newPoint(260,146),newPoint(232,100),},};// 手工构造层级信息,和上面的四条轮廓一一对应。varhierarchy=new[]{newHierarchyIndex(3,-1,1,-1),newHierarchyIndex(-1,-1,2,0),newHierarchyIndex(-1,-1,-1,1),newHierarchyIndex(-1,0,-1,-1),};usingvarcanvas=newMat(260,400,MatType.CV_8UC3,Scalar.White);usingvartarget=InputOutputArray.Create(canvas);// contourIdx=0 表示从第 1 条轮廓开始,maxLevel=2 表示展开两层子轮廓。Cv2.DrawContours(target,contours,0,newScalar(53,114,223),3,LineTypes.AntiAlias,hierarchy,2,null);// 保存图片,检查轮廓子树是否按预期绘制。Cv2.ImWrite("drawcontours-point-enumerable.png",canvas);}}

8. 注意事项

  1. contourIdx小于 0 时会绘制所有轮廓。
  2. maxLevel只有在提供层级信息时才有效。
  3. thickness < 0会触发填充模式。
  4. offset只是整体平移,不会改变轮廓形状。

9. 调优建议

  1. 如果只想高亮某个轮廓家族,优先控制contourIdxmaxLevel
  2. 想让子轮廓关系更清楚,可以给不同层级使用不同颜色再叠加说明。
  3. 如果要表达“里面还有洞”,建议先画外轮廓再画内轮廓。
  4. 教学时可以把轮廓编号写在边界附近,帮助初学者对照数组顺序。

10. 进阶扩展

  1. 可以把FindContours的结果直接拿来做这个函数的输入。
  2. 可以结合ContourAreaBoundingRect一起讲轮廓几何。
  3. 可以用offset做拖拽式轮廓平移。
  4. 可以用thickness=-1配合层级信息做填充掩膜。

11. 常见错误排查

  1. 误以为contourIdx=0会画全部轮廓。
  2. 没有层级信息却期待maxLevel产生递归效果。
  3. thickness < 0和正数线宽混淆。
  4. 忽略轮廓点顺序,导致图形方向和层级理解混乱。

相关链接:

  • WPF 教学控件:Cv2DrawContoursControl.xaml.cs
  • 样例实现:DrawContoursPointEnumerableSample.cs
  • 官方文档源码位置:OpenCvSharp/Cv2/Cv2_imgproc.cs
http://www.jsqmd.com/news/1068079/

相关文章:

  • 3A分子筛乙醇脱水的实验装置设计方案
  • 2026年第一、二季度最新最全热门网站建设工具全面对比评测
  • SpringCloud Alibaba Sentinel 限流+熔断完整实战教程
  • 电阻、电容、电感,二极管、三极管、mos管
  • 江科大PWM笔记:呼吸灯、舵机控制、电机调速
  • Linux 实时优化的端到端延迟:从中断到任务执行的全链路优化
  • 2026山东大学软件学院创新项目实训(团队——6)
  • 山东大学项目实训6月20日
  • 【编号317】西安城市边缘区土地利用数据
  • 计算机毕业设计之取保候审人员管理系统设计与实现
  • (一)站稳脚:用Scikit-learn跑通第一条Pipeline
  • SQL必知必会——使用游标
  • 【Springboot毕设全套源码+文档】基于springboot蛋糕店线上预订销售系统的设计与实现(丰富项目+远程调试+讲解+定制)
  • TAP/TUN与自定义网络协议栈
  • c#软件开发学习笔记--Winform窗体第二期
  • NAT导致视频监控平台无法拉取视频流故障一例
  • 上下文窗口、KV Cache 与长上下文问题
  • Kubernetes 之资源对象 Pod详解
  • Celery 和 Apache Airflow 都可用于定时任务调度与全量数据批量分析,但定位、架构和适用场景有显著区别
  • Java 集合 - Java集合框架详解与应用
  • 毕业设计 深度学习yolo藻类细胞检测识别(科研辅助系统)(源码+论文)
  • pikachu详细通关教程
  • YOLO系列目标检测数据集大全【第四十一期】
  • 基于 Harmony 6.0 应用的乡村助农直播应用首页实现
  • UniLaViRA/HumanoidMimicGen/VERA/Tabero/S-Cheetah/FGO六大具身SOTA全网独家复现|零样本跨体导航/人形数据扩增/视频动作映射/触觉柔顺控力/仿生四足
  • 视频协议传输全解析:从 HTTP/HTTPS 到 HLS/DASH 的完整旅程
  • Java 集合 - 用好 SortedMap 和 NavigableMap,优化 Java 集合排序与操作效率
  • 后端常见问题
  • 继电器项目
  • RAG 系统化学习教程(含查询改写、混合检索、重排序、上下文增强与评估闭环)