OpencvSharp 算子学习教案之 - Cv2.ConnectedComponents 重载3大家好Opencv在很多工程项目中都会用到而OpencvSharp则是以C#开发与实现的Opencv操作库对.NET开发人员友好但很多API的中文资料、应用场景及常见坑点等缺乏系统性归纳因此这系列博客将给大家带来Cv2及Mat对象全系列算子学习教案供大家参考学习。Cv2.ConnectedComponents教案版本V1.0面向对象OpenCvSharp 初学者所属模块imgproc源码位置OpenCvSharp/Cv2/Cv2_imgproc.cs:2745摘要本页演示Cv2.ConnectedComponents(InputArray, out int[,], PixelConnectivity)如何直接返回二维整数标签数组。这个重载很适合想在纯 C# 里继续遍历、筛选或持久化标签结果的场景。1. 函数名称带参数签名publicstaticintConnectedComponents(InputArrayimage,outint[,]labels,PixelConnectivityconnectivity)2. 函数用途Cv2.ConnectedComponents(..., out int[,], ...)用来把连通域结果直接返回成二维int数组。它最常见的用途有想在纯 C# 里继续处理标签图。想把标签结果做序列化、存档或传输。想在不依赖Mat的情况下做后续逻辑。想让教学代码更像“普通数组处理”降低入门门槛。这个重载特别适合初学者因为它把结果直接变成了 C# 里的二维数组。3. 函数公式这个重载的数学意义和默认重载一致只是输出容器变成了int[,]L ( p ) k L(p) kL(p)k其中L(p)是像素p的标签编号。k 0表示背景。k 0表示第k个前景连通块。前景块数仍然可以写成F o r e g r o u n d C o u n t L a b e l C o u n t − 1 ForegroundCount LabelCount - 1ForegroundCountLabelCount−14. 函数原理说明和输出Mat的版本相比这个重载的区别只在于“结果怎么装起来”。对初学者来说可以这样理解OpenCV 先完成连通域标记。OpenCvSharp 再把标签图转换成二维int数组。这样你就可以直接在 C# 中用labels[row, col]访问每个像素所属的连通块。这个重载最大的优点是简单直观最大的教学价值是让你更快理解“标签图其实就是一个二维编号表”。我们在示例里故意使用 4 连通这样对角桥上的像素会被拆成几个独立标签差异会更明显。5. 参数含义解析参数名类型必填含义imageInputArray是8 位单通道二值图labelsint[,]是输出二维整数标签数组connectivityPixelConnectivity是4 连通或 8 连通补充说明labels的行列和输入图完全对应。0 号标签仍然表示背景。4 连通会比 8 连通更严格。如果你只想在 C# 中做遍历这个重载非常方便。6. 应用场景列表场景名场景说明典型用途场景A数组遍历直接遍历labels[row, col]纯 C# 处理场景B结果存档把二维数组保存到文件数据持久化场景C规则筛选对特定标签做额外处理后续过滤场景D教学入门让初学者把标签图理解成编号表入门学习7. 函数使用示例与 WPF 场景一一对应说明下面示例对应 WPF 场景 C。它会直接拿到int[,]再把数组转回Mat做热力图显示。usingSystem;usingOpenCvSharp;internalstaticclassProgram{privatestaticvoidMain(){// 先准备一张二值图前景块的数量和位置都尽量简单、稳定方便观察。usingvarsourceCreateDemoImage();// 这个重载会直接把结果写成二维 int 数组很适合在纯 C# 里继续处理。varlabelCountCv2.ConnectedComponents(source,outint[,]labels,PixelConnectivity.Connectivity4);// 打印数组信息时先确认它的行列数和原图一致。Console.WriteLine($LabelCount {labelCount});Console.WriteLine($ForegroundCount {labelCount-1});Console.WriteLine($ArraySize {labels.GetLength(0)}x{labels.GetLength(1)});// 把二维数组转回 Mat再映射成热力图初学者更容易看见标签分布。usingvarlabelMatMat.FromPixelData(labels.GetLength(0),labels.GetLength(1),MatType.CV_32SC1,labels);SaveLabelHeatmap(labelMat,connected_int_array.png);}privatestaticMatCreateDemoImage(){// 背景保持为 0前景统一填 255满足连通域函数对二值图的要求。varcanvasnewMat(260,420,MatType.CV_8UC1,Scalar.All(0));// 两个大块通过对角像素连接便于对比 4 连通和 8 连通。Cv2.Rectangle(canvas,newRect(32,38,64,52),Scalar.All(255),-1,LineTypes.AntiAlias);Cv2.Rectangle(canvas,newRect(100,94,64,48),Scalar.All(255),-1,LineTypes.AntiAlias);for(varoffset0;offset4;offset){Cv2.Rectangle(canvas,newRect(96offset,90offset,1,1),Scalar.All(255),-1);}// 再补几个孤立块让数组里的标签编号更有层次。Cv2.Circle(canvas,newPoint(314,64),26,Scalar.All(255),-1,LineTypes.AntiAlias);Cv2.Ellipse(canvas,newPoint(296,186),newSize(36,26),12,0,360,Scalar.All(255),-1,LineTypes.AntiAlias);Cv2.Rectangle(canvas,newRect(44,176,54,38),Scalar.All(255),-1,LineTypes.AntiAlias);returncanvas;}privatestaticvoidSaveLabelHeatmap(Matlabels,stringfileName){// 标签编号本身只是整数所以先拉伸到 0~255 再套颜色映射最容易观察。usingvarlabels64newMat();labels.ConvertTo(labels64,MatType.CV_64FC1);usingvarnormalizednewMat();Cv2.Normalize(labels64,normalized,0,255,NormTypes.MinMax,MatType.CV_8UC1);usingvarheatmapnewMat();Cv2.ApplyColorMap(normalized,heatmap,ColormapTypes.Turbo);Cv2.ImWrite(fileName,heatmap);}}8. 常见错误与避坑误以为int[,]只适合小数据其实它只是更方便教学和纯 C# 处理。忘记数组的第一维是行第二维是列。以为 4 连通和 8 连通只是名字不同。直接把数组当成普通图像像素值去显示结果看不出标签编号。9. 进阶扩展可以把int[,]直接写入 CSV再交给其他程序分析。可以把数组转换回Mat后做颜色映射或绘图。可以把标签数组和stats表一起存下来形成完整的连通域分析结果。可以把 4 连通和 8 连通的数组结果并排比较。10. 小结Cv2.ConnectedComponents(..., out int[,], ...)的核心价值在于简单它直接给你一个二维整数数组。它很适合 C# 教学和后续遍历。它和Mat版本的数学含义完全一致。11. 相关链接WPF 教学控件Cv2ConnectedComponentsControl.xaml.cs样例实现ConnectedComponentsIntArraySample.cs官方文档源码位置OpenCvSharp/Cv2/Cv2_imgproc.cs:2745