【Halcon】Halcon模板匹配技术深度解析:形状匹配 vs 局部可形变匹配

Halcon模板匹配技术深度解析:形状匹配 vs 局部可形变匹配

前言

在工业视觉定位系统中,模板匹配是一项核心技术。Halcon提供了两种主流的模板匹配方法:形状匹配(Shape-Based Matching)局部可形变匹配(Local Deformable Matching)。本文将深入解析这两种匹配方式的特点、区别和实际应用场景,并结合实际代码实现进行说明。


一、两种匹配方式概述

1.1 形状匹配(Shape-Based Matching)

核心特点:

  • 基于边缘轮廓的刚性匹配
  • 支持平移、旋转、缩放变换
  • 匹配速度快,适合刚性物体
  • 返回位置(Row, Column)、角度(Angle)和缩放比例(Scale)

适用场景:

  • 刚性物体定位
  • 需要精确角度信息的场景
  • 对匹配速度要求较高的应用
  • 物体形状变化较小的场景

1.2 局部可形变匹配(Local Deformable Matching)

核心特点:

  • 允许模板局部变形
  • 适应物体形状的微小变化
  • 只返回位置(Row, Column),不返回角度
  • 返回变形后的轮廓(DeformedContours)
  • 匹配速度相对较慢,但鲁棒性更强

适用场景:

  • 柔性物体定位
  • 物体形状存在局部变形的场景
  • 对角度不敏感的应用
  • 需要高鲁棒性的复杂场景

二、核心差异对比

特性 形状匹配 局部可形变匹配
变换类型 刚性变换(平移+旋转+缩放) 可形变变换(平移+局部变形)
返回角度 ✅ 是 ❌ 否(角度为0)
返回轮廓 不返回轮廓,使用模板轮廓(需仿射变换) 直接返回变形轮廓(含位姿直接使用)
匹配速度 较慢
鲁棒性 中等
适用物体 刚性物体 柔性/可变形物体
轮廓显示 需要仿射变换 直接显示变形轮廓

三、核心概念:模板轮廓 vs 匹配轮廓

在深入代码实现之前,我们需要理解一个关键概念

3.1 模板轮廓(ModelContours)

⚠️ 重要:无论是形状匹配还是局部可形变匹配,从模板获取的轮廓(ModelContours)坐标位置都是原点(0,0)!

csharp 复制代码
// 形状匹配:获取模板轮廓
HOperatorSet.GetShapeModelContours(out ModelContours, ModelID, 1);
// ModelContours 的坐标位置 = (0, 0) ← 原点位置

// 局部可形变匹配:获取模板轮廓
HOperatorSet.GetDeformableModelContours(out ModelContours, ModelID, 1);
// ModelContours 的坐标位置 = (0, 0) ← 原点位置

特点:

  • ModelContours 只是模板的原始形状定义
  • 不包含任何位置信息,坐标始终在原点(0,0)
  • 需要后续变换才能显示到正确位置

3.2 匹配后的轮廓

形状匹配:

  • 不会返回轮廓信息,只返回基于原点的偏移值。
  • 需要根据匹配结果(Row, Column, Angle)进行仿射变换

局部可形变匹配:

  • 返回的是 DeformedContours已包含位姿信息
  • 坐标已经对应到图像中的匹配位置
  • 直接显示即可,无需变换

四、代码实现解析

4.1 模板加载阶段

形状匹配模板加载
csharp 复制代码
// 读取形状模板
ModelID = imageScriptTool.ReadShapeModel(fullPath, false);
// 获取模板轮廓(用于后续显示)
HOperatorSet.GetShapeModelContours(out ModelContours, ModelID, 1);
局部可形变匹配模板加载
csharp 复制代码
// 读取可形变模板
HOperatorSet.ReadDeformableModel(fullPath, out ModelID);
// 获取模板的原始轮廓(用于显示基准位置)
HOperatorSet.GetDeformableModelContours(out ModelContours, ModelID, 1);

关键区别:

  • 形状匹配使用 ReadShapeModelGetShapeModelContours
  • 局部可形变匹配使用 ReadDeformableModelGetDeformableModelContours

⚠️ 重要说明:

无论是形状匹配还是局部可形变匹配,从模板获取的轮廓(ModelContours坐标位置都是原点(0,0)。这些轮廓是模板的原始形状,不包含任何位置信息,需要后续的变换操作才能显示到正确的位置。

4.2 匹配执行阶段

形状匹配执行
csharp 复制代码
HOperatorSet.FindScaledShapeModel(finalImg,
    ModelID,
    start,              // 起始角度(弧度)
    range,              // 角度范围(弧度)
    templateInfo.MinScale,
    templateInfo.MaxScale,
    templateInfo.MinScore,
    templateInfo.NumMatches,
    templateInfo.MaxOverlap,
    templateInfo.SubPixel,
    templateInfo.NumLevels,
    templateInfo.Greediness,
    out RowMatch,       // 行坐标
    out ColumnMatch,    // 列坐标
    out AngleMatch,     // 角度(弧度)✅ 有角度信息
    out ScaleMatch,     // 缩放比例
    out Score);         // 匹配分数

返回结果:

  • RowMatch, ColumnMatch: 匹配位置
  • AngleMatch: 匹配角度(弧度)
  • ScaleMatch: 缩放比例
  • Score: 匹配分数
局部可形变匹配执行
csharp 复制代码
HOperatorSet.FindLocalDeformableModel(finalImg, 
    out _, 
    out _, 
    out DeformedContours,  // 变形轮廓 ✅ 直接返回变形后的轮廓
    ModelID,
    start,
    range,
    templateInfo.MinScale,
    templateInfo.MaxScale,
    templateInfo.MinScale,
    templateInfo.MaxScale,
    templateInfo.MinScore,
    templateInfo.NumMatches,
    templateInfo.MaxOverlap,
    templateInfo.NumLevels,
    templateInfo.Greediness,
    new HTuple("image_rectified", "vector_field", "deformed_contours"),
    new HTuple("deformation_smoothness", "expand_border", "subpixel"),
    new HTuple(templateInfo.Smoothness, 0, "least_squares"),
    out Score,
    out RowMatch,       // 行坐标
    out ColumnMatch);   // 列坐标
    // ❌ 没有角度信息,AngleMatch = 0

返回结果:

  • RowMatch, ColumnMatch: 匹配位置
  • DeformedContours: 变形后的轮廓 ✅ 直接可用
  • Score: 匹配分数
  • 角度信息:AngleMatch = 0

五、可视化显示的关键差异

CompareTemplatePosition 函数中,两种匹配方式的可视化显示逻辑有显著差异:

5.1 形状匹配的可视化

基准位置显示(绿色):

csharp 复制代码
// 创建仿射变换矩阵(平移 + 旋转)
HTuple baseMovementOfModel;
HOperatorSet.VectorAngleToRigid(0, 0, 0, 
    result.BaseRow, 
    result.BaseColumn, 
    baseAngleRad,  // ✅ 使用基准角度
    out baseMovementOfModel);

// 对模板轮廓进行仿射变换
HObject BaseContoursAffineTrans;
HOperatorSet.AffineTransContourXld(ModelContours, 
    out BaseContoursAffineTrans, 
    baseMovementOfModel);

// 显示绿色轮廓
hWindow.SetColor("green");
hWindow.DispObj(BaseContoursAffineTrans);

当前匹配位置显示(红色):

csharp 复制代码
// 创建仿射变换矩阵(平移 + 旋转)
HTuple currentMovementOfModel;
HOperatorSet.VectorAngleToRigid(0, 0, 0, 
    result.CurrentRow, 
    result.CurrentColumn, 
    currentAngleRad,  // ✅ 使用当前匹配角度
    out currentMovementOfModel);

// 对模板轮廓进行仿射变换
HObject CurrentContoursAffineTrans;
HOperatorSet.AffineTransContourXld(ModelContours, 
    out CurrentContoursAffineTrans, 
    currentMovementOfModel);

// 显示红色轮廓
hWindow.SetColor("red");
hWindow.DispObj(CurrentContoursAffineTrans);

关键点:

  • ✅ 使用**模板轮廓(ModelContours)**进行显示
  • ✅ 需要仿射变换(平移 + 旋转)
  • ✅ 角度信息来自匹配结果

5.2 局部可形变匹配的可视化

基准位置显示(绿色):

csharp 复制代码
// 创建平移变换矩阵(只有平移,角度=0)
HTuple baseMovementOfModel;
HOperatorSet.VectorAngleToRigid(0, 0, 0, 
    result.BaseRow, 
    result.BaseColumn, 
    0,  // ❌ 角度固定为0
    out baseMovementOfModel);

// 对原始轮廓进行平移变换
HObject BaseContoursAffineTrans;
HOperatorSet.AffineTransContourXld(ModelContours, 
    out BaseContoursAffineTrans, 
    baseMovementOfModel);

// 显示绿色轮廓
hWindow.SetColor("green");
hWindow.DispObj(BaseContoursAffineTrans);

当前匹配位置显示(红色):

csharp 复制代码
// ✅ 直接显示变形轮廓,无需任何变换!
if (DeformedContours != null && DeformedContours.IsInitialized())
{
    hWindow.SetColor("red");
    hWindow.DispObj(DeformedContours);  // 直接显示,无需变换
}

关键点:

  • ✅ 基准位置:使用原始轮廓(ModelContours,坐标在原点(0,0)) + 平移变换(角度=0)
  • ✅ 当前匹配位置:直接显示变形轮廓(DeformedContours,已包含位姿信息)无需仿射变换
  • ❌ 没有角度信息,所以基准位置只做平移
  • ⚠️ 重要ModelContours 坐标在原点(0,0),DeformedContours 已包含位置信息

六、为什么匹配后局部可形变匹配不需要仿射变换?从模板读取却需要?

这是很多开发者容易混淆的地方。让我们深入理解:

6.1 模板轮廓的共同特点

⚠️ 重要前提:无论是形状匹配还是局部可形变匹配,从模板获取的轮廓(ModelContours)坐标位置都是原点(0,0)!

csharp 复制代码
// 形状匹配:获取模板轮廓
HOperatorSet.GetShapeModelContours(out ModelContours, ModelID, 1);
// ModelContours 的坐标位置 = (0, 0)

// 局部可形变匹配:获取模板轮廓
HOperatorSet.GetDeformableModelContours(out ModelContours, ModelID, 1);
// ModelContours 的坐标位置 = (0, 0)

关键点:

  • ModelContours 只是模板的原始形状定义
  • 不包含任何位置信息,坐标始终在原点(0,0)
  • 需要后续变换才能显示到正确位置

6.2 形状匹配的轮廓变换

形状匹配返回的是:

  • 位置(Row, Column)← 基于原点的偏移值
  • 角度(Angle)
  • 不返回轮廓,需要使用模板轮廓(ModelContours)← 坐标在(0,0)

由于 ModelContours 的坐标在原点(0,0),要显示匹配结果,需要:

  1. 将轮廓从(0,0)平移到匹配位置(Row, Column)
  2. 将轮廓旋转到匹配角度(Angle)

因此需要仿射变换AffineTransContourXld):

csharp 复制代码
// 创建仿射变换矩阵(平移 + 旋转)
HTuple MovementOfModel;
HOperatorSet.VectorAngleToRigid(0, 0, 0, RowMatch, ColumnMatch, AngleMatch, out MovementOfModel);
// 对模板轮廓进行仿射变换
HOperatorSet.AffineTransContourXld(ModelContours, out ContoursAffineTrans, MovementOfModel);

6.3 局部可形变匹配的轮廓

局部可形变匹配返回的是:

  • 位置(Row, Column)
  • 变形轮廓 (DeformedContours)✅ 已经包含位姿信息的轮廓

关键区别:

DeformedContours 是 Halcon 在匹配过程中:

  1. 根据图像内容对模板进行局部变形
  2. 将变形后的轮廓直接定位到匹配位置已包含位置信息!

因此,DeformedContours 已经是最终结果 ,其坐标已经对应到图像中的匹配位置,直接显示即可,无需任何变换

代码注释也明确说明了这一点:

csharp 复制代码
//局部可形变的匹配直接生成DeformedContours,无需再做仿射变换!!!
// DeformedContours 已经包含了位姿信息(位置信息)

6.4 对比总结

匹配方式 模板轮廓位置 匹配后轮廓 是否需要变换
形状匹配 (0, 0) ModelContours(在原点) ✅ 需要仿射变换
局部可形变匹配 (0, 0) DeformedContours(已定位) ❌ 无需变换

核心理解:

  • 模板轮廓(ModelContours):两种方式都是从原点(0,0)开始
  • 形状匹配:不返回轮廓,只返回偏移值,需要使用模板轮廓进行手动变换
  • 局部可形变匹配:返回的轮廓(DeformedContours)已经包含了位姿信息,直接可用

七、实际应用场景建议

7.1 选择形状匹配的场景

推荐使用:

  • 印刷电路板(PCB)定位
  • 机械零件装配定位
  • 需要精确角度信息的场景
  • 对匹配速度要求高的应用
  • 物体形状变化很小的场景

示例:

csharp 复制代码
// PCB板上的定位孔,形状固定,需要精确角度
if (templateInfo.bLocalDeformable == false)
{
    // 使用形状匹配,获取精确的角度信息
    // 用于后续的旋转校正
}

7.2 选择局部可形变匹配的场景

推荐使用:

  • 柔性包装袋定位
  • 纺织品图案匹配
  • 橡胶制品定位
  • 物体形状存在局部变形的场景
  • 对角度不敏感的应用

示例:

csharp 复制代码
// 柔性包装袋,形状可能因包装过程产生局部变形
if (templateInfo.bLocalDeformable == true)
{
    // 使用局部可形变匹配,适应形状变化
    // 只关注位置,不关心角度
}

八、性能优化建议

8.1 避免重复匹配

CompareTemplatePosition 函数中,我们只进行一次匹配,结果同时用于:

  • 计算差值
  • 可视化显示
csharp 复制代码
// ✅ 只匹配一次
if (templateInfo.bLocalDeformable)
{
    HOperatorSet.FindLocalDeformableModel(finalImg, 
        out _, out _, out DeformedContours, ...);
    // 保存 DeformedContours,后续直接使用
}
else
{
    HOperatorSet.FindScaledShapeModel(finalImg, ...);
    // 保存 ModelContours,后续进行变换显示
}

8.2 资源管理

确保正确释放 Halcon 对象:

csharp 复制代码
// 释放变形轮廓
if (DeformedContours != null && DeformedContours.IsInitialized())
{
    DeformedContours.Dispose();
}

// 释放模板轮廓
if (ModelContours != null && ModelContours.IsInitialized())
{
    ModelContours.Dispose();
}

// 清理模板模型
if (templateInfo.bLocalDeformable)
{
    HOperatorSet.ClearDeformableModel(ModelID);
}
else
{
    HOperatorSet.ClearShapeModel(ModelID);
}

九、总结

核心要点回顾

  1. 模板轮廓的共同特点

    • ⚠️ 无论是形状匹配还是局部可形变匹配,从模板获取的轮廓(ModelContours)坐标位置都是原点(0,0)
    • ModelContours 只是模板的原始形状定义,不包含位置信息
  2. 形状匹配

    • ✅ 返回角度信息
    • ✅ 不返回轮廓,只返回基于原点的偏移值(Row, Column, Angle)
    • ✅ 需要使用模板轮廓(ModelContours,坐标在原点)进行仿射变换显示
    • ✅ 匹配速度快
    • ✅ 适合刚性物体
  3. 局部可形变匹配

    • ❌ 不返回角度(角度=0)
    • ✅ 返回的变形轮廓(DeformedContours)已包含位姿信息,直接显示无需变换
    • ⚠️ 匹配速度较慢
    • ✅ 适合柔性/可变形物体
  4. 可视化差异

    • 形状匹配:模板轮廓(坐标在原点) + 仿射变换(平移+旋转)
    • 局部可形变匹配:基准位置用原始轮廓(坐标在原点)+平移,当前位置直接显示变形轮廓(已包含位置信息)

选择建议

  • 需要角度信息 → 选择形状匹配
  • 物体形状固定 → 选择形状匹配
  • 物体形状可变 → 选择局部可形变匹配
  • 对速度要求高 → 选择形状匹配
  • 对鲁棒性要求高 → 选择局部可形变匹配

相关推荐
kylezhao20196 小时前
C#手写串口助手
开发语言·c#
向宇it6 小时前
2025年技术总结 | 在Unity游戏开发路上的持续探索与沉淀
游戏·unity·c#·游戏引擎
Tan38518 小时前
如何在 OfficeAI 上配置 API Key(图文教程)
开发语言·人工智能·c#·api·教程·officeai
薛勇8 小时前
.net中如何选择async/await 和Task.Run?
c#·.net
剑之所向8 小时前
c# 中间表
开发语言·c#
Lv11770088 小时前
初识Visual Studio中的 WinForm
开发语言·ide·笔记·c#·visual studio
AscendKing9 小时前
java poi word首行插入文字
java·c#·word
bugcome_com9 小时前
深入解析 C# 中 abstract class 与 interface 的核心差异
c#
wuguan_9 小时前
C#:自走棋项目
c#·自走棋