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);
关键区别:
- 形状匹配使用
ReadShapeModel和GetShapeModelContours - 局部可形变匹配使用
ReadDeformableModel和GetDeformableModelContours
⚠️ 重要说明:
无论是形状匹配还是局部可形变匹配,从模板获取的轮廓(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),要显示匹配结果,需要:
- 将轮廓从(0,0)平移到匹配位置(Row, Column)
- 将轮廓旋转到匹配角度(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 在匹配过程中:
- 根据图像内容对模板进行局部变形
- 将变形后的轮廓直接定位到匹配位置 ← 已包含位置信息!
因此,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);
}
九、总结
核心要点回顾
-
模板轮廓的共同特点:
- ⚠️ 无论是形状匹配还是局部可形变匹配,从模板获取的轮廓(ModelContours)坐标位置都是原点(0,0)
ModelContours只是模板的原始形状定义,不包含位置信息
-
形状匹配:
- ✅ 返回角度信息
- ✅ 不返回轮廓,只返回基于原点的偏移值(Row, Column, Angle)
- ✅ 需要使用模板轮廓(ModelContours,坐标在原点)进行仿射变换显示
- ✅ 匹配速度快
- ✅ 适合刚性物体
-
局部可形变匹配:
- ❌ 不返回角度(角度=0)
- ✅ 返回的变形轮廓(DeformedContours)已包含位姿信息,直接显示无需变换
- ⚠️ 匹配速度较慢
- ✅ 适合柔性/可变形物体
-
可视化差异:
- 形状匹配:模板轮廓(坐标在原点) + 仿射变换(平移+旋转)
- 局部可形变匹配:基准位置用原始轮廓(坐标在原点)+平移,当前位置直接显示变形轮廓(已包含位置信息)
选择建议
- 需要角度信息 → 选择形状匹配
- 物体形状固定 → 选择形状匹配
- 物体形状可变 → 选择局部可形变匹配
- 对速度要求高 → 选择形状匹配
- 对鲁棒性要求高 → 选择局部可形变匹配