OpencvSharp 算子学习教案之 - Cv2.MatchShapes 重载1
2026/6/5 8:59:58 网站建设 项目流程

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,doubleparameter=0)

2. 函数用途

Cv2.MatchShapes(...)用来比较两个轮廓的形状相似度。

这个重载最适合轮廓已经保存成Mat的场景:

  1. 输入可以直接来自前面的轮廓矩阵。
  2. 返回值是一个相似度分数,越小表示越像。
  3. 可以选择三种方法中的一种来比较。

它常用于:

  1. 形状检索。
  2. 目标轮廓筛选。
  3. 模板匹配的辅助判断。
  4. 初学者理解 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_{i=1}^{7}\left|\frac{1}{m_i^A}-\frac{1}{m_i^B}\right|I1(A,B)=i=17miA1miB1

I 2 ( A , B ) = ∑ i = 1 7 ∣ m i A − m i B ∣ I_2(A,B)=\sum_{i=1}^{7}\left|m_i^A-m_i^B\right|I2(A,B)=i=17miAmiB

I 3 ( A , B ) = max ⁡ i = 1 7 ∣ m i A − m i B ∣ ∣ m i A ∣ I_3(A,B)=\max_{i=1}^{7}\frac{\left|m_i^A-m_i^B\right|}{\left|m_i^A\right|}I3(A,B)=i=1max7miAmiAmiB

其中A AAB BB分别表示两个轮廓。

4. 函数原理说明

这个函数的重点,是把轮廓转换成能反映整体形状的 Hu 矩,再根据不同方法算出差异。

对初学者来说,最值得记住的是:

  1. 它比较的是形状,不是轮廓在图像里的位置。
  2. 对平移、旋转和缩放通常都比较鲁棒。
  3. 分数越小,两个轮廓越接近。

parameter目前在 OpenCvSharp 里还没有实际启用,所以教学时可以先把它理解成占位参数。

5. 参数含义解析

参数名类型必填含义
contour1InputArray第一个轮廓或灰度图像
contour2InputArray第二个轮廓或灰度图像
methodShapeMatchModes形状比较方法
parameterdouble方法相关参数,当前未启用

补充说明:

  1. 这里的InputArray最常见就是Mat形式的轮廓。
  2. 如果你比较的是轮廓,输入一般用PointPoint2f点集构造。
  3. ShapeMatchModes有三种常用值:I1I2I3

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,所以这里先把两组点包装成矩阵。usingvarreferenceMat=Mat.FromArray(referencePoints);usingvarcandidateMat=Mat.FromArray(candidatePoints);// 三种比较方法都算一遍,初学者就能直观看到每种方法的结果。doublescoreI1=Cv2.MatchShapes(referenceMat,candidateMat,ShapeMatchModes.I1);doublescoreI2=Cv2.MatchShapes(referenceMat,candidateMat,ShapeMatchModes.I2);doublescoreI3=Cv2.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. 常见错误与避坑

  1. 把 MatchShapes 误认为位置比较,它实际比较的是形状本身。
  2. 看到分数不是 0 就以为不对,实际上轻微变形后分数本来就会变化。
  3. 忽略method参数,导致无法理解三种评分方式的差异。
  4. parameter当成必须填写的关键参数,实际上当前版本还没启用。

9. 进阶扩展

  1. 可以同时比较多组轮廓,再按分数从小到大排序。
  2. 可以把 MatchShapes 和FindContours结合,做简单形状检索。
  3. 可以把三种方法的结果放在同一张表里对比。
  4. 可以先做轮廓平滑,再比较形状分数,观察结果是否更稳定。

10. 小结

Cv2.MatchShapes(...)的 InputArray 重载适合把已经整理好的轮廓直接拿来做形状比较。

如果你关心“长得像不像”,它通常比简单的面积、周长比较更有意义。

11. 相关链接

  • WPF 教学控件:Cv2MatchShapesControl.xaml.cs
  • 样例实现:MatchShapesInputArraySample.cs
  • 官方文档源码位置:OpenCvSharp/Cv2/Cv2_imgproc.cs
  • 另一个重载源码位置:OpenCvSharp/Cv2/Cv2_imgproc.cs

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询