
OpencvSharp 算子学习教案之 - Cv2.FloodFill 重载4大家好Opencv在很多工程项目中都会用到而OpencvSharp则是以C#开发与实现的Opencv操作库对.NET开发人员友好但很多API的中文资料、应用场景及常见坑点等缺乏系统性归纳因此这系列博客将给大家带来Cv2及Mat对象全系列算子学习教案供大家参考学习。Cv2.FloodFill教案版本V1.0面向对象OpenCvSharp 初学者所属模块imgproc源码位置OpenCvSharp/Cv2/Cv2_imgproc.cs:2374摘要这是 FloodFill 最完整的重载之一。它同时包含 image、mask、rect、loDiff / upDiff 和 flags最适合讲解“只改 mask、不改图像”的标注场景。1. 函数名称带参数签名publicstaticintFloodFill(InputOutputArrayimage,InputOutputArraymask,PointseedPoint,ScalarnewVal,outRectrect,Scalar?loDiffnull,Scalar?upDiffnull,FloodFillFlagsflagsFloodFillFlags.Link4)2. 函数用途这个重载是最完整的 FloodFill 版本。它常见于需要同时控制图像和 mask 的场景。想在区域生长后顺手拿到外接矩形的场景。想把 FloodFill 当作“区域标注工具”来用的场景。如果你希望初学者同时理解mask、rect和MaskOnly这个重载最合适。3. 函数公式把 mask 和 rect 也放进来可以写成R { p ∣ p 与 seed 连通 ∧ M ( p ) 0 ∧ ∣ I ( p ) − I ( s e e d ) ∣ ≤ δ } R \{p \mid p \text{ 与 seed 连通} \land M(p) 0 \land |I(p) - I(seed)| \le \delta\}R{p∣p与seed连通∧M(p)0∧∣I(p)−I(seed)∣≤δ}并且r e c t BoundingBox ( R ) rect \operatorname{BoundingBox}(R)rectBoundingBox(R)如果flags里带了MaskOnly那么图像本身不会改写只会更新 mask。4. 函数原理说明这个版本可以理解成三层控制图像颜色决定“能不能生长”。mask 决定“能不能越过这里”。rect 记录“最后生长到了哪里”。当你把MaskOnly加进去之后FloodFill 的意义就从“改图像”变成了“标注区域”。这对初学者很重要因为它能帮助你理解 mask 在分割中的实际作用。5. 参数含义解析参数名类型必填含义imageInputOutputArray是输入输出图像maskInputOutputArray是额外遮罩控制可扩张范围seedPointPoint是区域生长起点newValScalar是新填充值若开启MaskOnlyimage 不会被改写rectout Rect是填充区域的外接矩形loDiffScalar?否向下容忍差值upDiffScalar?否向上容忍差值flagsFloodFillFlags否连通方式和额外控制标志补充说明mask 仍然必须比原图大 2 像素。MaskOnly会让这个重载更像“打标记”而不是“改图像”。rect很适合帮助你理解“这块区域到底长到了哪里”。6. 应用场景列表场景名场景说明典型用途场景A只更新 mask图像不变只做区域标注半自动标注场景B同时看 rect观察区域扩张后的边界框面积统计场景C完整控制结合 mask、rect 和 flags 调整结果教学、调试7. 函数使用示例下面的 Console 程序会先构造一张绿色区域再用 mask 和MaskOnly把区域标出来。这个例子最适合帮助初学者理解图像不一定要变mask 也可以单独承担“区域标注”的任务。usingSystem;usingOpenCvSharp;internalstaticclassProgram{privatestaticvoidMain(){// 先准备一张浅色背景图方便看出区域生长后的边界框。usingvarimagenewMat(240,360,MatType.CV_8UC3,newScalar(244,241,236));// 这里画一个渐变绿色椭圆方便演示 MaskOnly 和 rect 的组合效果。Cv2.Ellipse(image,newPoint(170,122),newSize(64,54),0,0,360,newScalar(102,210,126),-1,LineTypes.AntiAlias);Cv2.Ellipse(image,newPoint(170,122),newSize(46,38),0,0,360,newScalar(122,226,150),-1,LineTypes.AntiAlias);Cv2.Ellipse(image,newPoint(170,122),newSize(64,54),0,0,360,newScalar(58,92,54),2,LineTypes.AntiAlias);// mask 尺寸必须比原图大 2 像素。usingvarmasknewMat(image.Rows2,image.Cols2,MatType.CV_8UC1,Scalar.All(0));Cv2.Rectangle(mask,newRect(0,0,mask.Cols,mask.Rows),Scalar.All(1),1,LineTypes.Link8);// 用一个闭合框圈住允许填充的范围。Cv2.Rectangle(mask,newRect(170-641,122-541,128,108),Scalar.All(255),2,LineTypes.Link8);varseedPointnewPoint(170,122);varnewColornewScalar(242,178,66);varloDiffnewScalar(12,12,12);varupDiffnewScalar(12,12,12);// MaskOnly 表示只更新 mask不改写图像本身。Rectrect;intfilledPixelsCv2.FloodFill(image,mask,seedPoint,newColor,outrect,loDiff,upDiff,FloodFillFlags.MaskOnly|FloodFillFlags.Link8|FloodFillFlags.FixedRange);Console.WriteLine(FloodFill 完整重载示例);Console.WriteLine($seed ({seedPoint.X},{seedPoint.Y}));Console.WriteLine($filled pixels {filledPixels});Console.WriteLine($rect {rect});Console.WriteLine($mask non-zero pixels {Cv2.CountNonZero(mask)});}}8. 运行结果解读filledPixels表示实际参与生长的像素数量。rect表示生长区域的外接矩形。如果MaskOnly打开图像本身保持不变变化只反映在 mask 里。这个重载很适合把 FloodFill 当成“标注器”而不是“改色器”来理解。9. 常见误区与注意事项MaskOnly不会改写 image这一点很容易被忽略。mask的尺寸仍然必须是原图加 2。newVal在MaskOnly模式下会被忽略但参数仍然要传。rect只是外接矩形不代表内部形状一定是矩形。loDiff/upDiff仍然要按 BGR 通道理解。10. 扩展思考如果把MaskOnly去掉图像会变成什么样。如果把rect画在原图上能不能更直观看出生长范围。如果把mask改成椭圆闭合边界区域会不会更像真实对象轮廓。11. 小结这个重载最完整也最适合把 FloodFill 的工作方式一次讲清楚。只要你记住 mask 决定边界、rect 记录范围、MaskOnly 决定是否改图像你就已经掌握了这个版本的核心语义。如果你想在本仓库里看更直观的结果请打开 Cv2FloodFillControl.xaml.cs 对应的页面。