halcon 入门教程(六) 图像匹配(基于形状的模板匹配)与缺陷检测区域定位

原文作者:aircraft

原文链接:https://www.cnblogs.com/DOMLX/p/18783476

有兴趣可以多看其他的halcon教程

halcon 学习教程目录

本篇主要讲一下工业中最常用的基于形状的模板匹配,以及根据模板定位锁定待检测区域的位置。注意本篇对于工业的缺陷检测是最基础的也是最重要的!!!如果你学习掌握了本篇的demo示例,基本一些简单的工业缺陷检测是没有什么大问题的。

本来应该是有个halcon的程序集里的示例代码的,但是我没找到比较短的,好入门的,所以我临时手写了一个halcon例子。至于其他的例子可以去看halcon官方的。

一.模板匹配简介

**  halcon中的模板匹配**‌是一种图像处理技术,主要用于在新的图像中找到特定模板图像的位置。模板匹配通过算法比较图像和模板之间的相似度,从而实现对目标的定位和识别。HALCON提供了多种模板匹配方法:

1. 基于点的匹配(Point-Based Matching)​

原理与特点

  • 核心机制 :通过提取图像中的关键点(如SIFT、SURF特征点)进行匹配,依赖局部特征描述符的相似度。
  • 优势
    • 视角变化(旋转、缩放、倾斜)鲁棒。
    • 部分遮挡(只要保留足够特征点即可匹配)。
  • 局限
    • 需要图像中存在丰富的纹理或角点。
    • 计算复杂度较高,实时性受限。

参数调优

  • 关键参数
    • 'keypoint_radius':特征点邻域半径,影响描述符的区分度。
    • 'min_score':匹配分数阈值,过滤低置信度匹配。

应用场景

  • 无人机航拍匹配:识别地标或建筑特征点。
  • 动态视角检测:如机器人抓取不同角度的工件。

2. 基于灰度值的匹配(Gray-Value-Based Matching)​

原理与特点

  • 核心机制 :直接比较模板与图像区域的像素灰度值相似度(如SSD、NCC)。
  • 优势
    • 计算极快,适合实时性要求高的场景。
    • 无需特征提取,适用于无纹理或低对比度图像。
  • 局限
    • 光照变化、旋转、缩放敏感。
    • 无法处理形变或遮挡。

参数调优

  • 关键参数
    • 'mask_size':匹配时的掩模大小,影响抗噪声能力。
    • 'subpixel':是否启用亚像素精度('true'/'false')。

应用场景

  • 印刷品定位:固定光源下检测标签位置。
  • 电子元件校准:如LED晶圆的对位。

3. 基于形状的匹配(Shape-Based Matching)​--------------工业场景中最常用的方法!!!

原理与特点

  • 核心机制 :提取模板的边缘轮廓,通过形状相似性(边缘梯度方向)进行匹配。
  • 优势
    • 抗光照变化(仅依赖边缘信息)。
    • 支持旋转、缩放(通过参数化设置范围)。
    • 工业场景中最常用的方法。
  • 局限
    • 边缘模糊或缺失敏感。
    • 需要清晰的轮廓定义。

参数调优

  • 关键参数
    • 'angle_step':角度搜索步长(越小越慢但精度↑)。
    • 'scale_min'/'scale_max':允许的缩放范围。
    • 'min_contrast':最小边缘对比度(过滤噪声)。

应用场景

  • 机械臂抓取:定位金属零件轮廓。
  • OCR预处理:定位文本区域。

4. 基于组件的匹配(Component-Based Matching)​

原理与特点

  • 核心机制 :将物体分解为多个子组件,分别匹配后组合结果。
  • 优势
    • 严重遮挡(只要保留关键子组件即可匹配)。
    • 适合复杂结构物体(如多部件装配体)。
  • 局限
    • 需定义子组件的空间关系(如相对位置、角度)。
    • 参数配置复杂。

参数调优

  • 关键参数
    • 'component_relation':子组件间的空间约束(如距离容差)。
    • 'min_component_score':单个子组件的最低匹配分数。

应用场景

  • 汽车装配检测:检查发动机组件的完整性。
  • 货架商品识别:部分遮挡下的商品匹配。

5. 基于局部可变形匹配(Locally Deformable Matching)​

原理与特点

  • 核心机制 :允许模板在匹配过程中发生局部非线性形变(如拉伸、弯曲)。
  • 优势
    • 处理弹性变形(如布料、橡胶件)。
    • 对局部缺损鲁棒。
  • 局限
    • 计算复杂度高,实时性差。
    • 需要高质量的模板图像。

参数调优

  • 关键参数
    • 'deformation_smoothness':形变平滑度约束(值越高形变越受限)。
    • 'max_deformation':最大允许形变量(像素单位)。

应用场景

  • 软包装检测:如食品袋的褶皱匹配。
  • 生物医学图像:器官组织的弹性变形分析。

6. 基于可变形的匹配(Deformable Matching)​

原理与特点

  • 核心机制 :通过参数化变形模型(仿射、透视变换)处理全局形变。
  • 优势
    • 支持透视变换和3D投影。
    • 可校正大范围视角倾斜。
  • 局限
    • 需要已知变形参数范围(如倾斜角度限制)。
    • 对非线性形变(如局部弯曲)处理能力有限。

参数调优

  • 关键参数
    • 'perspective_model':是否启用透视模型('true'/'false')。
    • 'max_deformation':最大形变参数值。

应用场景

  • 倾斜视角校正:如车牌识别。
  • AR/VR定位:虚拟物体的3D叠加。

错误排查指南

现象 可能原因 解决方案
匹配分数低 模板与图像差异大 检查光照、对比度,调整min_contrast
匹配时间过长 搜索范围过大 缩小角度/缩放范围,增大angle_step
误匹配多 阈值设置过松 提高min_score,启用max_overlap
无法创建模型 模板图像质量差 使用edges_image强化边缘

二.图像匹配以及缺陷区域定位

老规矩,直接上图:

我们接下来对一个零件建立模板,并且我们建立一个小孔区域的缺陷检测ROI区域,当我们匹配到这个零件的时候,检测缺陷的区域也会到当前零件的小孔位置去,这样我们就可以对其进行区域缺陷检测了(工业中非常常用!!!)

大概过程如下:

  1. 读取并显示图像;
  2. 绘制模板ROI及待检测ROI;
  3. 创建模型;
  4. 匹配模板;
  5. ROI仿射变换,得到待检测ROI位置。

第一步:画模板区域,框选了一颗零件矩形区域。

第二步:画待检测区域

第三步:创建模板,默认模板都在左上角,模板中心点没设置的话默认是模板的重心位置 自己可以用set_shape_model_origin(这个算子工业开发中会用到)算子设置一下,基本我们都是设置为裁剪区域的中心点。

第四步:匹配定位到模板,在将模板以及待检测区域的位置转换过去

第五步:就是检测这个区域了,这里简单的提取个中心显示一下,正常你们是要对其进行某些检测的。比如我在小孔这里画个白色的什么脏东西,你就可以用Blob分析去检测出来,或者这里小孔位置歪了,或者干脆没有小孔,那么你该怎么检测呢?

OK 实例的过程讲完了,我们在认识一下接下来要用到的算子,然后就直接看代码理解。

1.创建形状匹配模板算子create_shape_model ([Template](#1.创建形状匹配模板算子create_shape_model(Template : : NumLevels, AngleStart, AngleExtent, AngleStep, Optimization, Metric, Contrast, MinContrast : ModelID)详解:) : : [NumLevels](#1.创建形状匹配模板算子create_shape_model(Template : : NumLevels, AngleStart, AngleExtent, AngleStep, Optimization, Metric, Contrast, MinContrast : ModelID)详解:), [AngleStart](#1.创建形状匹配模板算子create_shape_model(Template : : NumLevels, AngleStart, AngleExtent, AngleStep, Optimization, Metric, Contrast, MinContrast : ModelID)详解:), [AngleExtent](#1.创建形状匹配模板算子create_shape_model(Template : : NumLevels, AngleStart, AngleExtent, AngleStep, Optimization, Metric, Contrast, MinContrast : ModelID)详解:), [AngleStep](#1.创建形状匹配模板算子create_shape_model(Template : : NumLevels, AngleStart, AngleExtent, AngleStep, Optimization, Metric, Contrast, MinContrast : ModelID)详解:), [Optimization](#1.创建形状匹配模板算子create_shape_model(Template : : NumLevels, AngleStart, AngleExtent, AngleStep, Optimization, Metric, Contrast, MinContrast : ModelID)详解:), [Metric](#1.创建形状匹配模板算子create_shape_model(Template : : NumLevels, AngleStart, AngleExtent, AngleStep, Optimization, Metric, Contrast, MinContrast : ModelID)详解:), [Contrast](#1.创建形状匹配模板算子create_shape_model(Template : : NumLevels, AngleStart, AngleExtent, AngleStep, Optimization, Metric, Contrast, MinContrast : ModelID)详解:), [MinContrast](#1.创建形状匹配模板算子create_shape_model(Template : : NumLevels, AngleStart, AngleExtent, AngleStep, Optimization, Metric, Contrast, MinContrast : ModelID)详解:) : [ModelID](#1.创建形状匹配模板算子create_shape_model(Template : : NumLevels, AngleStart, AngleExtent, AngleStep, Optimization, Metric, Contrast, MinContrast : ModelID)详解:))详解:

函数原型:

复制代码
create_shape_model(
    Template        : :  // 输入模板图像(ROI区域)
    NumLevels       : :  // 金字塔层级数
    AngleStart      : :  // 起始角度(弧度)
    AngleExtent     : :  // 角度范围(弧度)
    AngleStep       : :  // 角度步长(弧度或'auto')
    Optimization    : :  // 模型优化模式
    Metric          : :  // 匹配度量方式
    Contrast        : :  // 对比度参数(列表)
    MinContrast     : :  // 最小对比度阈值
    : ModelID           // 输出模型句柄
)

参数详解与工业配置策略

1. NumLevels (金字塔层级数)

  • 作用:控制模型的金字塔层级,层级越多,匹配速度越快,但会损失细节。 正常我们都是1-3之间设置自己摸索一下。
  • 推荐值
    • 高速场景:3-5层(如产线速度>30fps)
    • 高精度场景:1-3层(需亚像素精度)

2. AngleStartAngleExtent (角度范围)

  • 作用:定义模型在匹配时的旋转角度搜索范围。
  • 工业设置
    • 固定角度AngleStart=0, AngleExtent=0(无旋转)
    • 全角度检测AngleStart=0, AngleExtent=rad(360)
  • 案例
    • 传送带零件允许±30°倾斜 → AngleStart=rad(-30), AngleExtent=rad(60) 一般前面的绝对值是后面一半这样设置

3. AngleStep (角度步长)

  • 作用:角度搜索的步长,决定角度分辨率。
  • 设置策略
    • **'auto'**:自动计算(推荐优先使用)
    • 手动设置:根据精度需求调整(越小越精确但速度越慢)
      • 高速产线:rad(1.0)
      • 高精度检测:rad(0.1)

4. Optimization (优化模式)

  • 可选值
    • 'none':不优化(内存占用最小)
    • 'pregeneration':预生成模型(匹配最快,内存占用高)
    • 'no_pregeneration':不预生成(内存占用低,匹配稍慢)
  • 推荐
    • 实时检测'pregeneration'
    • 嵌入式设备'no_pregeneration'

5. Metric (匹配度量方式)

  • 选项
    • 'use_polarity':要求模板与目标对比度极性相同(亮/暗一致)
    • 'ignore_global_polarity':允许全局极性反转(如白底黑字→黑底白字)
    • 'ignore_local_polarity':允许局部极性变化(抗光照不均)
  • 工业场景
    • 金属零件检测 → 'use_polarity'
    • 印刷品检测(可变背景) → 'ignore_global_polarity'

6. ContrastMinContrast (对比度参数)

  • 作用:控制模型边缘特征的提取灵敏度。
  • 参数结构
    • Contrast:各金字塔层的对比度阈值(列表,长度=NumLevels)
    • MinContrast:模型允许的最小边缘对比度

案例1:高速产线零件定位

复制代码
* 参数配置
NumLevels := 4          // 4级金字塔加速匹配
AngleStep := 'auto'     // 自动角度步长
Optimization := 'pregeneration' // 预生成模型
Metric := 'use_polarity'// 极性一致(稳定光照)
Contrast := [25,12,6,3] // 各层对比度阈值
MinContrast := 5        // 最小边缘对比度

* 创建模型
create_shape_model (
    TemplateImage, 
    NumLevels, 
    rad(-30), rad(60),  // 允许±30°旋转
    AngleStep, 
    Optimization, 
    Metric, 
    Contrast, 
    MinContrast, 
    ModelID
)

案例2:低对比度塑料件检测

复制代码
* 参数配置
NumLevels := 2          // 高精度模式
AngleStep := rad(0.5)   // 小角度步长
Optimization := 'none'  // 节省内存
Metric := 'ignore_local_polarity' // 抗光照不均
Contrast := [10,5]      // 低对比度阈值
MinContrast := 3        // 捕捉微弱边缘

* 创建模型
create_shape_model (
    TemplateImage, 
    NumLevels, 
    rad(0), rad(360),   // 全角度搜索
    AngleStep, 
    Optimization, 
    Metric, 
    Contrast, 
    MinContrast, 
    ModelID
)

性能优化技巧

  1. 边缘滤波
    在创建模型前使用emphasizelaplace增强边缘对比度。
  2. ROI裁剪
    使用reduce_domain缩小模板区域,去除无关背景。
  3. 亚像素优化
    find_shape_model中启用'least_squares'亚像素模式。

通过精准配置create_shape_model参数,可兼顾速度与精度,满足工业检测的严苛要求。建议使用inspect_shape_model工具验证模型质量,并根据实际场景微调参数。

2.模板匹配算子find_shape_model ([Image](#2.模板匹配算子find_shape_model(Image : : ModelID, AngleStart, AngleExtent, MinScore, NumMatches, MaxOverlap, SubPixel, NumLevels, Greediness : Row, Column, Angle, Score)详解:) : : [ModelID](#2.模板匹配算子find_shape_model(Image : : ModelID, AngleStart, AngleExtent, MinScore, NumMatches, MaxOverlap, SubPixel, NumLevels, Greediness : Row, Column, Angle, Score)详解:), [AngleStart](#2.模板匹配算子find_shape_model(Image : : ModelID, AngleStart, AngleExtent, MinScore, NumMatches, MaxOverlap, SubPixel, NumLevels, Greediness : Row, Column, Angle, Score)详解:), [AngleExtent](#2.模板匹配算子find_shape_model(Image : : ModelID, AngleStart, AngleExtent, MinScore, NumMatches, MaxOverlap, SubPixel, NumLevels, Greediness : Row, Column, Angle, Score)详解:), [MinScore](#2.模板匹配算子find_shape_model(Image : : ModelID, AngleStart, AngleExtent, MinScore, NumMatches, MaxOverlap, SubPixel, NumLevels, Greediness : Row, Column, Angle, Score)详解:), [NumMatches](#2.模板匹配算子find_shape_model(Image : : ModelID, AngleStart, AngleExtent, MinScore, NumMatches, MaxOverlap, SubPixel, NumLevels, Greediness : Row, Column, Angle, Score)详解:), [MaxOverlap](#2.模板匹配算子find_shape_model(Image : : ModelID, AngleStart, AngleExtent, MinScore, NumMatches, MaxOverlap, SubPixel, NumLevels, Greediness : Row, Column, Angle, Score)详解:), [SubPixel](#2.模板匹配算子find_shape_model(Image : : ModelID, AngleStart, AngleExtent, MinScore, NumMatches, MaxOverlap, SubPixel, NumLevels, Greediness : Row, Column, Angle, Score)详解:), [NumLevels](#2.模板匹配算子find_shape_model(Image : : ModelID, AngleStart, AngleExtent, MinScore, NumMatches, MaxOverlap, SubPixel, NumLevels, Greediness : Row, Column, Angle, Score)详解:), [Greediness](#2.模板匹配算子find_shape_model(Image : : ModelID, AngleStart, AngleExtent, MinScore, NumMatches, MaxOverlap, SubPixel, NumLevels, Greediness : Row, Column, Angle, Score)详解:) : [Row](#2.模板匹配算子find_shape_model(Image : : ModelID, AngleStart, AngleExtent, MinScore, NumMatches, MaxOverlap, SubPixel, NumLevels, Greediness : Row, Column, Angle, Score)详解:), [Column](#2.模板匹配算子find_shape_model(Image : : ModelID, AngleStart, AngleExtent, MinScore, NumMatches, MaxOverlap, SubPixel, NumLevels, Greediness : Row, Column, Angle, Score)详解:), [Angle](#2.模板匹配算子find_shape_model(Image : : ModelID, AngleStart, AngleExtent, MinScore, NumMatches, MaxOverlap, SubPixel, NumLevels, Greediness : Row, Column, Angle, Score)详解:), [Score](#2.模板匹配算子find_shape_model(Image : : ModelID, AngleStart, AngleExtent, MinScore, NumMatches, MaxOverlap, SubPixel, NumLevels, Greediness : Row, Column, Angle, Score)详解:))详解:

函数原型:

复制代码
find_shape_model(
    Image       : :          // 输入图像(单通道灰度)
    ModelID     : :          // 形状模型句柄
    AngleStart  : :          // 起始角度(弧度)
    AngleExtent : :          // 角度范围(弧度)
    MinScore    : :          // 最小匹配分数(0-1)
    NumMatches  : :          // 最大匹配数量
    MaxOverlap  : :          // 最大重叠度(0-1)
    SubPixel    : :          // 亚像素模式
    NumLevels   : :          // 搜索金字塔层级范围([起始层, 结束层])
    Greediness  : :          // 贪婪系数(0-1)
    : Row, Column, Angle, Score  // 输出坐标、角度及分数
)

参数详解与工业配置策略

1. AngleStartAngleExtent

  • 作用 :限定匹配时的角度搜索范围,减少计算量。
  • 推荐设置技巧
    • 固定角度AngleStart=0, AngleExtent=0
    • 允许±30°旋转AngleStart=rad(-30), AngleExtent=rad(60)
  • 若模型创建时已限定角度范围,此处应保持一致。

2. MinScore (最小匹配分数)

  • 作用:过滤低质量匹配(范围0~1,1为完全匹配)。
  • 工业建议
    • 高精度检测 → 0.7-0.9
    • 高速场景 → 0.5-0.7

3. NumMatches (最大匹配数量)

  • 作用:限制返回的匹配结果数量。
  • 场景
    • 单一目标定位 → 1
    • 多目标检测 → 根据图像中预期目标数设置(如5)

4. MaxOverlap (最大重叠度)

  • 作用:控制重叠区域的匹配结果去重。
  • 设置规则
    • 密集排列物体 → 0.3-0.5
    • 孤立物体 → 0.8(几乎不抑制)

5. SubPixel (亚像素模式)

  • 选项
    • 'none':禁用(最快)
    • 'interpolation':插值法(平衡)
    • 'least_squares':最小二乘优化(最精确)
  • 推荐
    • 坐标精度要求≤0.5像素'least_squares'
    • 实时检测'interpolation''none'

6. NumLevels (金字塔层级范围)

  • 格式[起始层, 结束层](需≤创建模型时的金字塔层数)
  • 策略
    • 高速优先[3,1](从低分辨率到高分辨率)
    • 精度优先[0,2](从高分辨率开始)

7. Greediness (贪婪系数)

  • 作用 :平衡速度漏检率(值越高速度越快,但可能漏检)。
  • 建议
    • 稳定环境 → 0.7-0.9
    • 复杂背景 → 0.4-0.6

案例1:高精度零件定位(亚像素+严格过滤)

复制代码
find_shape_model (
    Image, ModelID, 
    rad(-10), rad(20),   // 允许±10°旋转
    0.8,                 // 最小分数0.8
    1,                   // 只找最佳匹配
    0.5,                 // 最大重叠度0.5
    'least_squares',     // 亚像素优化
    [0, 3],              // 使用所有金字塔层
    0.7,                 // 中等贪婪度
    Row, Column, Angle, Score
)

案例2:高速产线多目标检测

复制代码
find_shape_model (
    Image, ModelID,
    0, rad(360),         // 全角度搜索
    0.6,                 // 容忍较低分数
    5,                   // 最多5个匹配
    0.3,                 // 抑制重叠>30%的结果
    'interpolation',     // 快速亚像素
    [2, 1],              // 从第2层开始搜索
    0.9,                 // 高贪婪度
    Row, Column, Angle, Score
)

错误排查与调试

现象 可能原因 解决方案
无匹配结果 MinScore过高 逐步降低至0.3,观察是否出现匹配
匹配位置偏移 亚像素模式未启用 设置SubPixel='least_squares'
检测时间过长 Greediness过低 逐步提高至0.9
重复匹配同一物体 MaxOverlap过低 调整至0.6-0.8

最佳实践总结

  1. 参数联动调整 :创建模型时的Contrast与搜索时的NumLevels需协同优化。
  2. 结果验证 :使用dev_display_shape_matching_results可视化匹配结果。
  3. 资源释放 :循环结束后调用clear_shape_model避免内存泄漏。

通过合理配置find_shape_model参数,可在工业检测中实现高精度高速度的物体定位。

3.旋转矩阵生成算子hom_mat2d_rotate ( : : [HomMat2D](#3.旋转矩阵生成算子hom_mat2d_rotate( : : HomMat2D, Phi, Px, Py : HomMat2DRotate)详解:), [Phi](#3.旋转矩阵生成算子hom_mat2d_rotate( : : HomMat2D, Phi, Px, Py : HomMat2DRotate)详解:), [Px](#3.旋转矩阵生成算子hom_mat2d_rotate( : : HomMat2D, Phi, Px, Py : HomMat2DRotate)详解:), [Py](#3.旋转矩阵生成算子hom_mat2d_rotate( : : HomMat2D, Phi, Px, Py : HomMat2DRotate)详解:) : [HomMat2DRotate](#3.旋转矩阵生成算子hom_mat2d_rotate( : : HomMat2D, Phi, Px, Py : HomMat2DRotate)详解:))详解:

函数原型:

复制代码
hom_mat2d_rotate(
    : : 
    HomMat2D,      // 输入齐次变换矩阵
    Phi,           // 旋转角度(弧度,正值逆时针)
    Px, Py,        // 旋转中心坐标(原始坐标系中的点)
    : HomMat2DRotate // 输出旋转后的变换矩阵
)

参数解释

  • HomMat2D:输入的二维齐次变换矩阵。若初始为单位矩阵,表示无先前变换。
  • Phi :旋转角度(弧度)。例如,rad(30) 表示逆时针旋转30度。
  • Px, Py :旋转中心在原始坐标系中的坐标。无论之前的变换如何,旋转始终绕此点进行。
  • HomMat2DRotate:输出的新变换矩阵,将输入矩阵与旋转变换组合。

功能描述

  • 旋转变换 :生成的矩阵会先执行原始变换(HomMat2D),再绕原始坐标系 中的点 (Px, Py) 旋转角度 Phi
  • 矩阵组合:新矩阵 = 旋转变换矩阵 × 原始矩阵。即,先应用原始变换,再执行旋转。

示例1:绕图像中心旋转30度

复制代码
* 读取图像并获取尺寸
read_image(Image, 'part.png')
get_image_size(Image, Width, Height)

* 计算图像中心坐标
CenterX := Width / 2
CenterY := Height / 2

* 创建初始单位矩阵
hom_mat2d_identity(HomMat2D)

* 绕中心点旋转30度(逆时针)
hom_mat2d_rotate(HomMat2D, rad(30), CenterX, CenterY, HomMat2DRotate)

* 应用变换到图像
affine_trans_image(Image, ImageRotated, HomMat2DRotate, 'constant', 'false')

示例2:平移后绕新位置旋转

复制代码
* 将物体平移到(200,200),再绕该点旋转45度
hom_mat2d_identity(HomMat2D)
hom_mat2d_translate(HomMat2D, 200, 200, HomMat2DTranslate)
hom_mat2d_rotate(HomMat2DTranslate, rad(45), 200, 200, HomMat2DRotate)

* 应用变换到区域
affine_trans_region(Region, RegionTrans, HomMat2DRotate, 'nearest_neighbor')

关键注意事项

  1. 旋转中心(Px, Py) 必须是原始坐标系中的坐标。若之前的变换已移动物体,需计算其在原始坐标系中的目标位置。
  2. 变换顺序 :新矩阵按 旋转 × 原始 组合,意味着先执行原始变换,再旋转。
  3. 角度方向 :正值表示逆时针旋转,使用 rad() 函数转换角度。

错误排查

  • 非预期旋转中心 :检查 Px, Py 是否在原始坐标系中计算。
  • 角度错误 :确认使用弧度而非角度,例如 rad(30) 而非直接 30

可视化验证

使用 affine_trans_pixel 变换关键点并绘制,确认旋转中心正确:

复制代码
* 变换旋转中心点(应保持不变)
affine_trans_pixel(HomMat2DRotate, Px, Py, TransPx, TransPy)
gen_cross_contour_xld(Cross, TransPy, TransPx, 20, 0.785398) 
dev_display(Image)
dev_display(Cross) 

4.平移矩阵生成算子hom_mat2d_translate ( : : [HomMat2D](#4.平移矩阵生成算子hom_mat2d_translate( : : HomMat2D, Tx, Ty : HomMat2DTranslate)详解:), [Tx](#4.平移矩阵生成算子hom_mat2d_translate( : : HomMat2D, Tx, Ty : HomMat2DTranslate)详解:), [Ty](#4.平移矩阵生成算子hom_mat2d_translate( : : HomMat2D, Tx, Ty : HomMat2DTranslate)详解:) : [HomMat2DTranslate](#4.平移矩阵生成算子hom_mat2d_translate( : : HomMat2D, Tx, Ty : HomMat2DTranslate)详解:))详解:

函数原型:

复制代码
hom_mat2d_translate(
    : : 
    HomMat2D,          // 输入齐次变换矩阵
    Tx, Ty,            // X/Y方向平移量(像素单位)
    : HomMat2DTranslate // 输出平移后的变换矩阵
)

参数详解

参数名 类型 说明
HomMat2D 矩阵 输入的二维齐次变换矩阵。若初始为单位矩阵(无变换),可通过hom_mat2d_identity创建。
Tx, Ty 数值 X和Y方向的平移量(像素单位)。正值为向右/下平移,负值为向左/上平移。
HomMat2DTranslate 矩阵 输出矩阵,包含原矩阵的变换叠加平移后的结果。

功能描述

  • 作用 :在现有变换矩阵的基础上叠加平移变换,生成新的变换矩阵。
  • 数学原理
    若原矩阵为 H ,平移矩阵为 T,则新矩阵为:

这意味着先执行原矩阵的变换,再进行平移

示例1:纯平移变换(无初始变换)

复制代码
* 创建单位矩阵(无变换)
hom_mat2d_identity(HomMat2D)
* 向右平移50像素,向下平移30像素
hom_mat2d_translate(HomMat2D, 50, 30, HomMat2DTranslate)
* 应用平移变换到图像
affine_trans_image(Image, ImageTranslated, HomMat2DTranslate, 'constant', 'false')

示例2:组合变换(旋转+平移)

复制代码
* 绕图像中心旋转30度后,再平移
hom_mat2d_identity(HomMat2D)
* 计算图像中心坐标
get_image_size(Image, Width, Height)
CenterX := Width / 2
CenterY := Height / 2
* 旋转
hom_mat2d_rotate(HomMat2D, rad(30), CenterX, CenterY, HomMat2DRotate)
* 平移(在旋转后的坐标系中平移)
hom_mat2d_translate(HomMat2DRotate, 100, -50, HomMat2DTranslate)
* 应用复合变换
affine_trans_image(Image, ImageTransformed, HomMat2DTranslate, 'constant', 'false')

注意事项

  1. 变换顺序
    矩阵乘法顺序决定变换执行顺序。例如:
    • 先旋转后平移 → 物体绕原点旋转,再移动到新位置。
    • 先平移后旋转 → 物体移动到新位置后绕该点旋转。
复制代码
* 顺序不同,结果不同!
hom_mat2d_rotate → hom_mat2d_translate : 旋转后平移
hom_mat2d_translate → hom_mat2d_rotate : 平移后旋转
  • 坐标系基准
    平移量 (Tx, Ty) 始终基于原始坐标系。若之前有旋转/缩放,需手动计算偏移方向。
  • 复合变换验证
    使用affine_trans_pixel验证关键点变换结果:
复制代码
* 测试点 (0,0) 的变换结果
affine_trans_pixel(HomMat2DTranslate, 0, 0, Qx, Qy)
disp_message(WindowHandle, '平移后坐标: (' + Qx + ',' + Qy + ')', 'window', 10, 10, 'black', 'true')

错误排查

现象 原因 解决方案
平移方向相反 坐标系方向理解错误 HALCON中Y轴向下为正,检查符号。
变换结果偏离预期 变换顺序错误 调整hom_mat2d_rotatehom_mat2d_translate调用顺序。
平移后图像边缘被裁剪 未扩展画布 使用affine_trans_image时设置'adapt_size'参数为'true'

5.仿射变换算子(轮廓)affine_trans_contour_xld ([Contours](#5.仿射变换算子(轮廓)affine_trans_contour_xld(Contours : ContoursAffineTrans : HomMat2D : )详解:) : [ContoursAffineTrans](#5.仿射变换算子(轮廓)affine_trans_contour_xld(Contours : ContoursAffineTrans : HomMat2D : )详解:) : [HomMat2D](#5.仿射变换算子(轮廓)affine_trans_contour_xld(Contours : ContoursAffineTrans : HomMat2D : )详解:) : )详解:

函数原型:

复制代码
affine_trans_contour_xld(
    Contours             : :  // 输入:原始XLD轮廓
    HomMat2D            : :  // 输入:2D仿射变换矩阵
    : ContoursAffineTrans  // 输出:变换后的XLD轮廓
)

功能描述

  • 作用 :将输入的 XLD轮廓 通过指定的仿射变换矩阵 HomMat2D 进行几何变换(平移、旋转、缩放、剪切等),生成变换后的新轮廓。
  • 数学原理
    对轮廓中的每个点 (x, y) 应用变换:

其中 (x', y') 是变换后的坐标。

参数说明

参数 类型 说明
Contours XLD对象 输入的XLD轮廓(如边缘、多边形等)。
HomMat2D 矩阵 二维齐次变换矩阵,由 hom_mat2d_rotatehom_mat2d_translate 等生成。
ContoursAffineTrans XLD对象 输出的变换后轮廓,保留原始属性(如闭合性、点顺序)。

案例1:平移矩形轮廓

复制代码
* 创建矩形XLD轮廓
gen_rectangle2_contour_xld (Rectangle, 100, 100, 0, 50, 30)

* 生成平移变换矩阵(向右50像素,向下30像素)
hom_mat2d_identity (HomMat2D)
hom_mat2d_translate (HomMat2D, 50, 30, HomMat2DTranslate)

* 应用平移变换
affine_trans_contour_xld (Rectangle, HomMat2DTranslate, RectangleTrans)

案例2:绕中心旋转并缩放

复制代码
* 生成圆形XLD轮廓
gen_circle_contour_xld (Circle, 200, 200, 50, 0, 6.28318, 'positive', 1)

* 绕中心点(200,200)旋转30度并缩放0.8倍
hom_mat2d_identity (HomMat2D)
hom_mat2d_rotate (HomMat2D, rad(30), 200, 200, HomMat2DRotate)
hom_mat2d_scale (HomMat2DRotate, 0.8, 0.8, 200, 200, HomMat2DScale)

* 应用复合变换
affine_trans_contour_xld (Circle, HomMat2DScale, CircleTrans)

关键注意事项

  1. 变换顺序
    矩阵乘法顺序决定变换执行顺序。例如:
复制代码
* 先平移后旋转 vs 先旋转后平移
hom_mat2d_translate → hom_mat2d_rotate → 平移后旋转
hom_mat2d_rotate → hom_mat2d_translate → 旋转后平移
  1. 坐标系方向
    HALCON图像坐标系原点在左上角,x轴向右,y轴向下。变换矩阵中的坐标需与此一致。

  2. 性能优化

    • 避免频繁变换:若需多次应用相同变换,可预计算矩阵。
    • 使用hom_mat2d_invert快速逆变换。

应用场景

  1. 目标定位
    将模板轮廓变换到检测位置,用于匹配验证。
  2. 运动补偿
    动态调整轮廓以跟踪运动物体。
  3. 图像配准
    对齐不同视角或时间点的轮廓数据。

错误排查

现象 可能原因 解决方案
变换后轮廓消失 矩阵错误导致轮廓移出图像范围 检查变换参数或扩展图像区域。
轮廓形状畸变 缩放/剪切参数不合理 验证矩阵是否包含非法操作(如负缩放)。
性能低下 高密度轮廓+复杂变换 简化轮廓或优化矩阵生成逻辑。

6.仿射变换算子(区域)affine_trans_region ([Region](#6.仿射变换算子(区域)affine_trans_region(Region : RegionAffineTrans : HomMat2D, Interpolate : )详解:) : [RegionAffineTrans](#6.仿射变换算子(区域)affine_trans_region(Region : RegionAffineTrans : HomMat2D, Interpolate : )详解:) : [HomMat2D](#6.仿射变换算子(区域)affine_trans_region(Region : RegionAffineTrans : HomMat2D, Interpolate : )详解:), [Interpolate](#6.仿射变换算子(区域)affine_trans_region(Region : RegionAffineTrans : HomMat2D, Interpolate : )详解:) : )详解:

函数原型:

复制代码
affine_trans_region(
    Region            : :  // 输入:待变换的区域(Region)
    HomMat2D         : :  // 输入:二维齐次变换矩阵
    Interpolate      : :  // 输入:插值方法(区域像素处理方式)
    : RegionAffineTrans  // 输出:变换后的区域
)

参数详解

参数 类型 说明
Region Region 输入区域(需为非空区域)。
HomMat2D Matrix 二维齐次变换矩阵,由 hom_mat2d_rotatehom_mat2d_scale 等生成。
Interpolate String 插值方法,控制变换后区域的像素填充方式,可选值:'nearest_neighbor'(最近邻,速度快)、'bilinear'(双线性插值,边缘更平滑)、'constant'(固定值填充)。
RegionAffineTrans Region 输出区域,执行仿射变换后的结果。

核心功能

  1. 几何变换
    对输入区域执行 平移、旋转、缩放、剪切 等复合变换,生成新区域。

  2. 插值控制

    根据 Interpolate 参数选择不同的像素处理策略:

    • **'nearest_neighbor'**:速度快,但边缘可能产生锯齿(适合二值区域)。
    • **'bilinear'**:边缘平滑,适合需要亚像素精度的场景(如测量)。
    • **'constant'**:用固定灰度值填充空白区域(需配合 set_grayval 使用)。

示例1:旋转区域(工业零件定位)

复制代码
* 创建初始矩形区域
gen_rectangle1 (Region, 100, 100, 200, 300)

* 生成旋转变换矩阵(绕左上角原点旋转30度)
hom_mat2d_identity (HomMat2D)
hom_mat2d_rotate (HomMat2D, rad(30), 0, 0, HomMat2DRotate)

* 应用变换(使用双线性插值保持边缘平滑)
affine_trans_region (Region, HomMat2DRotate, 'bilinear', RegionRotated)

示例2:平移+缩放区域(图像ROI调整)

复制代码
* 生成复合变换矩阵(先缩放0.5倍,再平移)
hom_mat2d_identity (HomMat2D)
hom_mat2d_scale (HomMat2D, 0.5, 0.5, 0, 0, HomMat2DScale)
hom_mat2d_translate (HomMat2DScale, 50, 100, HomMat2DTranslate)

* 应用变换(最近邻插值,快速处理)
affine_trans_region (Region, HomMat2DTranslate, 'nearest_neighbor', RegionTrans)

应用场景

  1. 目标姿态调整
    将检测到的区域变换到标准位置,用于后续测量或比对。
  2. ROI动态跟踪
    根据运动估计更新感兴趣区域的位置和角度。
  3. 图像增强
    生成旋转/缩放的训练数据(数据增强)。

注意事项

  1. 插值选择

    • 二值区域 → 优先使用 'nearest_neighbor'(避免灰度插值引入噪声)。
    • 灰度区域 → 选择 'bilinear''constant'(保持边缘平滑)。
  2. 性能优化

    • 对二值区域,'nearest_neighbor''bilinear' 快3-5倍
    • 提前裁剪区域(reduce_domain)以减少计算量。
  3. 边界处理

    • 若变换后区域超出图像范围,超界部分会被自动裁剪。
    • 使用 full_domain 恢复完整区域(可能包含无效像素)。

可视化验证

复制代码
* 显示原始区域和变换后的区域
dev_display (Region)
dev_set_color ('green')
dev_display (RegionAffineTrans)

* 显示变换矩阵作用点(如旋转中心)
affine_trans_pixel (HomMat2D, 0, 0, TransX, TransY)
gen_cross_contour_xld (Cross, TransY, TransX, 20, 0.785)
dev_display (Cross)

7.生成刚体变换矩阵算子vector_angle_to_rigid ( : : [Row1](#7.生成刚体变换矩阵算子vector_angle_to_rigid( : : Row1, Column1, Angle1, Row2, Column2, Angle2 : HomMat2D)详解:), [Column1](#7.生成刚体变换矩阵算子vector_angle_to_rigid( : : Row1, Column1, Angle1, Row2, Column2, Angle2 : HomMat2D)详解:), [Angle1](#7.生成刚体变换矩阵算子vector_angle_to_rigid( : : Row1, Column1, Angle1, Row2, Column2, Angle2 : HomMat2D)详解:), [Row2](#7.生成刚体变换矩阵算子vector_angle_to_rigid( : : Row1, Column1, Angle1, Row2, Column2, Angle2 : HomMat2D)详解:), [Column2](#7.生成刚体变换矩阵算子vector_angle_to_rigid( : : Row1, Column1, Angle1, Row2, Column2, Angle2 : HomMat2D)详解:), [Angle2](#7.生成刚体变换矩阵算子vector_angle_to_rigid( : : Row1, Column1, Angle1, Row2, Column2, Angle2 : HomMat2D)详解:) : [HomMat2D](#7.生成刚体变换矩阵算子vector_angle_to_rigid( : : Row1, Column1, Angle1, Row2, Column2, Angle2 : HomMat2D)详解:))详解:

函数原型:

复制代码
vector_angle_to_rigid(
    : : 
    Row1, Column1, Angle1,   // 原始坐标系下的参考点及角度
    Row2, Column2, Angle2,   // 目标坐标系下的参考点及角度
    : HomMat2D                // 输出的刚体变换矩阵
)

参数详解

参数 类型 说明
Row1, Column1 浮点数 原始坐标系中的参考点坐标(如模板中心点)。
Angle1 浮点数 原始坐标系中的角度(弧度),通常为0(模板的初始角度)。
Row2, Column2 浮点数 目标坐标系中的参考点坐标(如检测到的目标中心点)。
Angle2 浮点数 目标坐标系中的角度(弧度),表示相对于原始角度的旋转量。
HomMat2D 矩阵 输出的2D刚体变换矩阵(包含平移和旋转,无缩放/剪切)。

功能描述

  • 作用 :生成一个刚体变换矩阵,将原始参考点 (Row1, Column1) 旋转并平移到目标参考点 (Row2, Column2),同时将角度 Angle1 调整到 Angle2
  • 数学原理
    变换矩阵 H 的构成:
  • R 为旋转矩阵(角度差为 Angle2 - Angle1
  • T 为平移矩阵(平移量为 (Row2 - Row1, Column2 - Column1)

场景1:模板匹配后的姿态对齐

复制代码
* 假设模板中心为(100,100),角度为0
* 检测到目标中心为(150,200),旋转角度为30°
vector_angle_to_rigid(100, 100, 0, 150, 200, rad(30), HomMat2D)
* 将模板区域变换到目标位置
affine_trans_region(TemplateRegion, RegionTrans, HomMat2D, 'nearest_neighbor')

场景2:机械臂抓取坐标转换

复制代码
* 视觉系统检测到物体中心为(300,250),旋转角度45°
* 机械臂坐标系需要平移到(500,600),并调整角度到0°
vector_angle_to_rigid(300, 250, rad(45), 500, 600, 0, HomMat2D)
* 转换抓取点坐标
affine_trans_pixel(HomMat2D, GraspX, GraspY, TransX, TransY)

零件旋转角度补偿

复制代码
* 读取图像并定位目标
read_image(Image, 'part.png')
find_shape_model(Image, ModelID, ..., Row, Column, Angle, Score)

* 生成刚体变换矩阵(从模板原点(0,0)到检测位置)
vector_angle_to_rigid(0, 0, 0, Row, Column, Angle, HomMat2D)

* 变换模板ROI到目标位置
affine_trans_region(TemplateROI, TransformedROI, HomMat2D, 'nearest_neighbor')

* 在变换后的ROI内执行检测
reduce_domain(Image, TransformedROI, ImageCropped)
threshold(ImageCropped, Region, 0, 128)

关键注意事项

  1. 角度单位
    HALCON中角度必须使用弧度 ,可用rad(角度)转换,如 rad(30) 表示30度。

  2. 坐标系方向
    HALCON图像坐标系原点在左上角,Y轴向下。若与机械臂坐标系(通常Y轴向上)不一致,需额外转换。

  3. 复合变换
    若需叠加缩放或剪切,需手动组合矩阵:

复制代码
* 先缩放后刚体变换
hom_mat2d_scale(HomMat2D, 0.5, 0.5, 0, 0, HomMat2DScale)
hom_mat2d_compose(HomMat2DScale, HomMat2D, HomMat2DCombined)

可视化验证

复制代码
* 显示变换前后关键点
gen_cross_contour_xld(Cross1, Row1, Column1, 20, 0.785)  // 原始点
gen_cross_contour_xld(Cross2, Row2, Column2, 20, 0.785)  // 目标点
affine_trans_contour_xld(Cross1, HomMat2D, Cross1Trans)  // 变换后的点
dev_display(Image)
dev_display(Cross1)
dev_display(Cross2)
dev_display(Cross1Trans)  // 应重合于Cross2

关于矩阵知识的是大学的线性代数课程,有兴趣可以学一下我这篇博客:关于opengl中的三维矩阵平移代码,矩阵旋转代码,推导过程理解 OpenGL计算机图形学的一些必要矩阵运算知识 glTranslatef(x,y,z)glRotatef(angle,x,y,z)函数详解

接下来进入正题实例代码(注释我都打好了,结合上面的算子和矩阵你们应该还是非常好理解的,这个demo会了以后,正常的工业检测都是这样的套路,先找到个不变得模板定位,然后将区域转换过去检测):

对已经定位到的区域进行检测的一些方法总结也可以看看这篇博客,或者我的halcon入门教程(五):

halcon------缺陷检测常用方法总结(光度立体)

复制代码
* 打开一个黑色背景的显示窗口,用于后续图像和结果的展示
dev_open_window (0, 0, 1000, 1000, 'black', WindowHandle)
* 获取当前窗口句柄,用于后续绘图操作
dev_get_window (WindowHandle1)

* 读取图像文件并转换为灰度图像
read_image (Image, '0.bmp')
*如果已经是单通道图像直接忽略
rgb1_to_gray (Image, GrayImage)

* -------- 模板区域定义 ---------
* 在窗口上手动绘制矩形ROI(用于创建模板)   这边选择的是带方向的矩形,也可以直接画普通矩形
draw_rectangle2 (WindowHandle1, RowMod, ColumnMod, PhiMod, LengthMod1, LengthMod2)
* 根据绘制的参数生成矩形区域对象
gen_rectangle2 (Rectangle1, RowMod, ColumnMod, PhiMod, LengthMod1, LengthMod2)
* 裁剪出矩形区域的图像(模板图像)
reduce_domain (GrayImage, Rectangle1, ImageReduced1)

* -------- 检测区域定义 ---------
* 在窗口上手动绘制第二个矩形ROI(用于检测区域)
draw_rectangle2 (WindowHandle1, Row1, Column1, Phi, Length1, Length2)
gen_rectangle2 (Rectangle, Row1, Column1, Phi, Length1, Length2)
* 裁剪检测区域图像
reduce_domain (GrayImage, Rectangle, ImageReduced)
* 对检测区域进行阈值分割(灰度0~80)
threshold (ImageReduced, Region, 0, 80)
* 计算区域面积和中心坐标
area_center (Region, Area, Row222, Column222)

* -------- 形状模板建模 ---------
* 创建形状匹配模型(金字塔级别=3,全角度搜索)
* 参数说明:
*   [14,31,4] : 最小对比度参数(金字塔各级对比度阈值)
*   6        : 模型生成时的最大边缘噪声容限
create_shape_model (ImageReduced1, 3, rad(0), rad(360), rad(1.5523), ['none','no_pregeneration'], 'use_polarity', [14,31,4], 6, ModelID)
* 获取模型的轮廓用于可视化
get_shape_model_contours (ModelContours, ModelID, 1)

* -------- 图像预处理 ---------
* 对原图进行25度旋转(模拟物体倾斜场景)
rotate_image (GrayImage, ImageRotate, 25, 'constant')

* -------- 形状匹配过程 ---------
* 在旋转后的图像中搜索模板
* 参数说明:
*   [3,2]     : 金字塔级别范围(从3到2级)  越大速度越快精度越低,1-3之间是比较合适的
*   0.75      : 最小匹配分数阈值
*   'least_squares' : 亚像素精度优化方法  一般固定选择一个就行
find_shape_model (ImageRotate, ModelID, rad(0), rad(360), 0.5, 0, 0.5, 'least_squares', [3,2], 0.75, Row, Column, Angle, Score)

* -------- 匹配结果后处理 ---------
for Index := 0 to |Row|-1 by 1
    * 生成仿射变换矩阵  后面两步的前置变量生成,说白了就是随便创建个矩阵变量
    hom_mat2d_identity (HomMat2D)
    * 将矩阵叠加旋转和平移变换  想象一下:后两个参数为0 就是绕自身旋转调整角度后直接平移  不为0就是绕某点坐标选择
    hom_mat2d_rotate (HomMat2D, Angle[Index], 0, 0, HomMat2D)
    hom_mat2d_translate (HomMat2D, Row[Index], Column[Index], HomMat2D)
    
    * 通过前面设置的移动矩阵参数  将模板轮廓变换到匹配位置
    affine_trans_contour_xld (ModelContours, TransContours, HomMat2D)
    dev_display (TransContours)  
    * 显示变换后的轮廓

    * 生成刚体变换矩阵(从模板原点变换到匹配位置)这个给后面的检测区域变换使用  
    *RowMod  ColumnMod是绘制检测区域的中心点 想象一下:让这个区域跟随你的模板匹配走一样路程到相对应的位置
    vector_angle_to_rigid (RowMod, ColumnMod, 0,  Row[Index], Column[Index], Angle[Index], HomMat2D2)
    
    * 将检测区域ROI变换到匹配位置
    affine_trans_region (Rectangle, RegionAffineTrans2, HomMat2D2, 'nearest_neighbor')
    * 在变换后的ROI内进行阈值分割
    reduce_domain (ImageRotate, RegionAffineTrans2, ImageReduced2)
    threshold (ImageReduced2, Region2, 0, 80)
    
    * 计算并显示目标中心点
    area_center (Region2, Area2, Row4, Column4)
    gen_cross_contour_xld (Cross, Row4, Column4, 15, 0)  
    * 生成十字标记
endfor
clear_shape_model (ModelID)

* 注意:实际工业应用中需添加以下内容:
* 1. 错误处理(try/catch)
* 2. 模型资源释放(clear_shape_model)
* 3. 匹配分数过滤(如只保留Score>0.65的结果)
* 4. 坐标单位转换(像素到物理尺寸)