蓬庄静 发表于 2025-6-2 00:29:35

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区域,当我们匹配到这个零件的时候,检测缺陷的区域也会到当前零件的小孔位置去,这样我们就可以对其进行区域缺陷检测了(工业中非常常用!!!)
大概过程如下:

[*]读取并显示图像;
[*]绘制模板ROI及待检测ROI;
[*]创建模型;
[*]匹配模板;
[*]ROI仿射变换,得到待检测ROI位置。
 
 
第一步:画模板区域,框选了一颗零件矩形区域。

 
第二步:画待检测区域
 

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

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

 

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

 
 OK 实例的过程讲完了,我们在认识一下接下来要用到的算子,然后就直接看代码理解。
 
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. AngleStart 与 AngleExtent (角度范围)


[*]​作用:定义模型在匹配时的旋转角度搜索范围。
[*]​工业设置:

[*]​固定角度: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. Contrast 与 MinContrast (对比度参数)


[*]​作用:控制模型边缘特征的提取灵敏度。
[*]​参数结构:

[*]Contrast:各金字塔层的对比度阈值(列表,长度=NumLevels)
[*]MinContrast:模型允许的最小边缘对比度

 

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

* 参数配置
NumLevels := 4          // 4级金字塔加速匹配
AngleStep := 'auto'   // 自动角度步长
Optimization := 'pregeneration' // 预生成模型
Metric := 'use_polarity'// 极性一致(稳定光照)
Contrast := // 各层对比度阈值
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 :=       // 低对比度阈值
MinContrast := 3      // 捕捉微弱边缘

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

性能优化技巧


[*]​边缘滤波:
在创建模型前使用emphasize或laplace增强边缘对比度。
[*]​ROI裁剪:
使用reduce_domain缩小模板区域,去除无关背景。
[*]​亚像素优化:
在find_shape_model中启用'least_squares'亚像素模式。
通过精准配置create_shape_model参数,可兼顾速度与精度,满足工业检测的严苛要求。建议使用inspect_shape_model工具验证模型质量,并根据实际场景微调参数。
 
 
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. AngleStart 与 AngleExtent


[*]​作用:限定匹配时的角度搜索范围,减少计算量。
[*]​推荐设置:​技巧:

[*]​固定角度 → 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.01或者0.1,不要设置成0)


[*]​作用:控制重叠区域的匹配结果去重。
[*]​设置规则:

[*]​密集排列物体 → 0.3-0.5
[*]​孤立物体 → 0.8(几乎不抑制)

5. SubPixel (亚像素模式)


[*]​选项:

[*]'none':禁用(最快)
[*]'interpolation':插值法(平衡)
[*]'least_squares':最小二乘优化(最精确)

[*]​推荐:

[*]​坐标精度要求≤0.5像素 → 'least_squares'
[*]​实时检测 → 'interpolation' 或 'none'

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


[*]​格式:[起始层, 结束层](需≤创建模型时的金字塔层数)可以理解成两次匹配,一次粗匹配一次细匹配一般我们这样设置【3-2】或者【2-1】
[*]​策略:

[*]​高速优先 → (从低分辨率到高分辨率)
[*]​精度优先 → (从高分辨率开始)

7. Greediness (贪婪系数)


[*]​作用:平衡速度与漏检率​(值越高速度越快,但可能漏检,一般我们设置0.98最高,也是不要设置到1)。
[*]​建议:

[*]​稳定环境 → 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.7,               // 中等贪婪度
    Row, Column, Angle, Score

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

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

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


[*]​参数联动调整:创建模型时的Contrast与搜索时的NumLevels需协同优化。
[*]​结果验证:使用dev_display_shape_matching_results可视化匹配结果。
[*]​资源释放:循环结束后调用clear_shape_model避免内存泄漏。
通过合理配置find_shape_model参数,可在工业检测中实现高精度、高速度的物体定位。
 
 
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') 
关键注意事项


[*]​旋转中心:(Px, Py) 必须是原始坐标系中的坐标。若之前的变换已移动物体,需计算其在原始坐标系中的目标位置。
[*]​变换顺序:新矩阵按 旋转 × 原始 组合,意味着先执行原始变换,再旋转。
[*]​角度方向:正值表示逆时针旋转,使用 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, 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')注意事项


[*]​变换顺序:
矩阵乘法顺序决定变换执行顺序。例如:

[*]​先旋转后平移 → 物体绕原点旋转,再移动到新位置。
[*]​先平移后旋转 → 物体移动到新位置后绕该点旋转。


* 顺序不同,结果不同!
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_rotate和hom_mat2d_translate调用顺序。平移后图像边缘被裁剪未扩展画布使用affine_trans_image时设置'adapt_size'参数为'true'。 
 
5.仿射变换算子(轮廓)affine_trans_contour_xld(Contours : ContoursAffineTrans : HomMat2D : )详解:
函数原型:
 
affine_trans_contour_xld(
    Contours             : :// 输入:原始XLD轮廓
    HomMat2D            : :// 输入:2D仿射变换矩阵
    : ContoursAffineTrans// 输出:变换后的XLD轮廓

 
功能描述



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


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

参数类型说明ContoursXLD对象输入的XLD轮廓(如边缘、多边形等)。HomMat2D矩阵二维齐次变换矩阵,由 hom_mat2d_rotate、hom_mat2d_translate 等生成。ContoursAffineTransXLD对象输出的变换后轮廓,保留原始属性(如闭合性、点顺序)。 
案例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) 
关键注意事项


[*]​变换顺序:
矩阵乘法顺序决定变换执行顺序。例如:

 
 
* 先平移后旋转 vs 先旋转后平移
hom_mat2d_translate → hom_mat2d_rotate → 平移后旋转
hom_mat2d_rotate → hom_mat2d_translate → 旋转后平移 

[*]坐标系方向:
HALCON图像坐标系原点在左上角,x轴向右,y轴向下。变换矩阵中的坐标需与此一致。
[*]​性能优化:

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

应用场景


[*]​目标定位:
将模板轮廓变换到检测位置,用于匹配验证。
[*]​运动补偿:
动态调整轮廓以跟踪运动物体。
[*]​图像配准:
对齐不同视角或时间点的轮廓数据。
错误排查

​现象​可能原因​解决方案变换后轮廓消失矩阵错误导致轮廓移出图像范围检查变换参数或扩展图像区域。轮廓形状畸变缩放/剪切参数不合理验证矩阵是否包含非法操作(如负缩放)。性能低下高密度轮廓+复杂变换简化轮廓或优化矩阵生成逻辑。 
 
 
 
 
6.仿射变换算子(区域)affine_trans_region(Region : RegionAffineTrans : HomMat2D, Interpolate : )详解:
函数原型:
affine_trans_region(
    Region            : :// 输入:待变换的区域(Region)
    HomMat2D         : :// 输入:二维齐次变换矩阵
    Interpolate      : :// 输入:插值方法(区域像素处理方式)
    : RegionAffineTrans// 输出:变换后的区域
)参数详解

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


[*]​几何变换
对输入区域执行 ​平移、旋转、缩放、剪切 等复合变换,生成新区域。
[*]​插值控制
根据 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) 
应用场景


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

注意事项


[*]​插值选择:

[*]​二值区域 → 优先使用 'nearest_neighbor'(避免灰度插值引入噪声)。
[*]​灰度区域 → 选择 'bilinear' 或 'constant'(保持边缘平滑)。

[*]​性能优化:

[*]对二值区域,'nearest_neighbor' 比 'bilinear' ​快3-5倍。
[*]提前裁剪区域(reduce_domain)以减少计算量。

[*]​边界处理:

[*]若变换后区域超出图像范围,超界部分会被自动裁剪。
[*]使用 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, 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)关键注意事项


[*]​角度单位:
HALCON中角度必须使用弧度,可用rad(角度)转换,如 rad(30) 表示30度。
[*]​坐标系方向:
HALCON图像坐标系原点在左上角,Y轴向下。若与机械臂坐标系(通常Y轴向上)不一致,需额外转换。
[*]​复合变换:
若需叠加缩放或剪切,需手动组合矩阵:

* 先缩放后刚体变换
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,全角度搜索)
* 参数说明:
*    : 最小对比度参数(金字塔各级对比度阈值)
*   6      : 模型生成时的最大边缘噪声容限
create_shape_model (ImageReduced1, 3, rad(0), rad(360), rad(1.5523), ['none','no_pregeneration'], 'use_polarity', , 6, ModelID)
* 获取模型的轮廓用于可视化
get_shape_model_contours (ModelContours, ModelID, 1)

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

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

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

    * 生成刚体变换矩阵(从模板原点变换到匹配位置)这个给后面的检测区域变换使用
    *RowModColumnMod是绘制检测区域的中心点 想象一下:让这个区域跟随你的模板匹配走一样路程到相对应的位置
    vector_angle_to_rigid (RowMod, ColumnMod, 0,Row, Column, Angle, 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. 坐标单位转换(像素到物理尺寸) 

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: halcon 入门教程(七) 图像匹配(基于形状的模板匹配)与缺陷检测区域定位