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

OpencvSharp 算子学习教案之 - Cv2.MatchShapes 重载1 OpencvSharp 算子学习教案之 - Cv2.MatchShapes 重载1大家好Opencv在很多工程项目中都会用到而OpencvSharp则是以C#开发与实现的Opencv操作库对.NET开发人员友好但很多API的中文资料、应用场景及常见坑点等缺乏系统性归纳因此这系列博客将给大家带来Cv2及Mat对象全系列算子学习教案供大家参考学习。Cv2.MatchShapes教案版本V1.0面向对象OpenCvSharp 初学者所属模块imgproc源码位置OpenCvSharp/Cv2/Cv2_imgproc.cs:3491 / 3514摘要本页演示MatchShapes(InputArray, InputArray, ShapeMatchModes, double)如何把两个Mat轮廓转成 Hu 矩比较分数并说明分数越小越相似。1. 函数名称带参数签名publicstaticdoubleMatchShapes(InputArraycontour1,InputArraycontour2,ShapeMatchModesmethod,doubleparameter0)2. 函数用途Cv2.MatchShapes(...)用来比较两个轮廓的形状相似度。这个重载最适合轮廓已经保存成Mat的场景输入可以直接来自前面的轮廓矩阵。返回值是一个相似度分数越小表示越像。可以选择三种方法中的一种来比较。它常用于形状检索。目标轮廓筛选。模板匹配的辅助判断。初学者理解 Hu 矩和形状不变性的入门示例。3. 函数公式MatchShapes 基于 Hu 矩比较两条轮廓的整体形状。OpenCV 文档把三种方法写成m i sign ⁡ ( h i ) ⋅ log ⁡ ( h i ) m_i \operatorname{sign}(h_i)\cdot \log(h_i)mi​sign(hi​)⋅log(hi​)I 1 ( A , B ) ∑ i 1 7 ∣ 1 m i A − 1 m i B ∣ I_1(A,B)\sum_{i1}^{7}\left|\frac{1}{m_i^A}-\frac{1}{m_i^B}\right|I1​(A,B)i1∑7​​miA​1​−miB​1​​I 2 ( A , B ) ∑ i 1 7 ∣ m i A − m i B ∣ I_2(A,B)\sum_{i1}^{7}\left|m_i^A-m_i^B\right|I2​(A,B)i1∑7​​miA​−miB​​I 3 ( A , B ) max ⁡ i 1 7 ∣ m i A − m i B ∣ ∣ m i A ∣ I_3(A,B)\max_{i1}^{7}\frac{\left|m_i^A-m_i^B\right|}{\left|m_i^A\right|}I3​(A,B)i1max7​​miA​​​miA​−miB​​​其中A AA和B BB分别表示两个轮廓。4. 函数原理说明这个函数的重点是把轮廓转换成能反映整体形状的 Hu 矩再根据不同方法算出差异。对初学者来说最值得记住的是它比较的是形状不是轮廓在图像里的位置。对平移、旋转和缩放通常都比较鲁棒。分数越小两个轮廓越接近。parameter目前在 OpenCvSharp 里还没有实际启用所以教学时可以先把它理解成占位参数。5. 参数含义解析参数名类型必填含义contour1InputArray是第一个轮廓或灰度图像contour2InputArray是第二个轮廓或灰度图像methodShapeMatchModes是形状比较方法parameterdouble否方法相关参数当前未启用补充说明这里的InputArray最常见就是Mat形式的轮廓。如果你比较的是轮廓输入一般用Point或Point2f点集构造。ShapeMatchModes有三种常用值I1、I2和I3。6. 应用场景列表场景名场景说明典型用途场景A轮廓检索找出最像的目标轮廓目标识别场景B形状筛选判断两个对象像不像分类预筛场景C教学对比观察三种方法的分数差异OpenCvSharp 入门场景D鲁棒性验证比较变换后的同形轮廓几何分析7. 函数使用示例与 WPF 场景一一对应说明下面示例对应 WPF 场景 A。它把两个轮廓先包装成Mat再分别用三种方法计算相似度。usingSystem;usingSystem.Globalization;usingOpenCvSharp;internalstaticclassProgram{privatestaticvoidMain(){// 参考轮廓直接复用一组较稳定的多边形点方便读者集中观察“形状比较”这件事。Point2f[]referencePoints{newPoint2f(76.5f,96.0f),newPoint2f(164.0f,58.5f),newPoint2f(262.0f,74.0f),newPoint2f(304.0f,136.0f),newPoint2f(286.0f,214.0f),newPoint2f(196.0f,262.0f),newPoint2f(92.5f,234.0f),newPoint2f(58.0f,150.0f),};// 候选轮廓先做一点缩放和旋转再轻微拉动一个顶点故意让它“很像但不是完全一样”。Point2f[]candidatePoints{newPoint2f(120.0f,82.0f),newPoint2f(188.0f,92.0f),newPoint2f(250.0f,124.0f),newPoint2f(266.0f,194.0f),newPoint2f(212.0f,248.0f),newPoint2f(144.0f,252.0f),newPoint2f(92.0f,198.0f),newPoint2f(88.0f,126.0f),};// MatchShapes 的 InputArray 重载可以直接接收 Mat所以这里先把两组点包装成矩阵。usingvarreferenceMatMat.FromArray(referencePoints);usingvarcandidateMatMat.FromArray(candidatePoints);// 三种比较方法都算一遍初学者就能直观看到每种方法的结果。doublescoreI1Cv2.MatchShapes(referenceMat,candidateMat,ShapeMatchModes.I1);doublescoreI2Cv2.MatchShapes(referenceMat,candidateMat,ShapeMatchModes.I2);doublescoreI3Cv2.MatchShapes(referenceMat,candidateMat,ShapeMatchModes.I3);Console.WriteLine($ReferenceCount {referencePoints.Length});Console.WriteLine($CandidateCount {candidatePoints.Length});Console.WriteLine($I1 {scoreI1.ToString(E6,CultureInfo.InvariantCulture)});Console.WriteLine($I2 {scoreI2.ToString(E6,CultureInfo.InvariantCulture)});Console.WriteLine($I3 {scoreI3.ToString(E6,CultureInfo.InvariantCulture)});Console.WriteLine($ReferenceArea {Math.Abs(Cv2.ContourArea(referencePoints)).ToString(F2,CultureInfo.InvariantCulture)});Console.WriteLine($CandidateArea {Math.Abs(Cv2.ContourArea(candidatePoints)).ToString(F2,CultureInfo.InvariantCulture)});// 这一行是本例的核心分数越小两个轮廓越相似。Console.WriteLine(MatchShapes 的结果越接近 0说明两个形状越像。\n);}}8. 常见错误与避坑把 MatchShapes 误认为位置比较它实际比较的是形状本身。看到分数不是 0 就以为不对实际上轻微变形后分数本来就会变化。忽略method参数导致无法理解三种评分方式的差异。把parameter当成必须填写的关键参数实际上当前版本还没启用。9. 进阶扩展可以同时比较多组轮廓再按分数从小到大排序。可以把 MatchShapes 和FindContours结合做简单形状检索。可以把三种方法的结果放在同一张表里对比。可以先做轮廓平滑再比较形状分数观察结果是否更稳定。10. 小结Cv2.MatchShapes(...)的 InputArray 重载适合把已经整理好的轮廓直接拿来做形状比较。如果你关心“长得像不像”它通常比简单的面积、周长比较更有意义。11. 相关链接WPF 教学控件Cv2MatchShapesControl.xaml.cs样例实现MatchShapesInputArraySample.cs官方文档源码位置OpenCvSharp/Cv2/Cv2_imgproc.cs另一个重载源码位置OpenCvSharp/Cv2/Cv2_imgproc.cs