很多做机器视觉的朋友私信问我,手里的项目到底要不要从 20.11 升到 HALCON 22.05 Progress,升完之后以前写的算子脚本能不能直接用,深度学习那套流程是不是真的像宣传说的那样顺手。我把这段时间在 22.05 上做迁移、写新功能、调性能、上产线的完整过程整理成了一份笔记,这篇就把其中最核心、最容易踩坑、也最值得看的部分挑出来讲透。
这套笔记适合正在用 HALCON 做视觉定位、测量、缺陷检测的工程师,也适合刚接触 HALCON、想直接了解 22.05 全貌的新人。我不打算按官方发布说明的条目顺序复述,而是按照我自己实际使用时的逻辑来组织:先搞清楚这个版本底层改了什么,再谈环境、算子、深度学习、性能优化,最后用两个真实排查案例收尾。
1. 22.05 Progress:这个版本究竟改了哪些底层东西
1.1 版本号里“Progress”是什么意思
先解释一下版本命名。以前大家习惯用“XX.X 大版本”来记,比如 HALCON 20.11、21.05。而 Progress 是官方这两年主推的订阅式滚动发布机制,22.05 的意思就是 2022 年的第二个进度版本。对使用者来说,最大的变化不是某一年憋一个大版本,而是每隔几个月就会收到一批更新,新特性、算子增强、性能优化是持续流进来的。
这个节奏对我这种常年做项目的人来说其实是好事。以前等大版本更新,新特性来了往往还要等生态适配;现在小步快跑,每次更新的量不大,迁移成本低,出现问题的排查范围也更小。但我必须提醒一句:如果你不是订阅模式,手上还是旧版的永久授权,那升级到 22.05 之前一定要确认好许可形态,这一点后面专门说。
1.2 我实际感知明显的更新点
官方的发布说明很长,我这里只挑我在真实项目中感知强烈的部分。
| 方向 | 我体感明显的变化 | 适用场景 |
|---|---|---|
| 自动算子并行化 | 并行策略更智能,多核利用率提升明显 | 批量图片处理、大图分割 |
| 深度学习推理与训练 | 语义分割、异常检测链路更顺,OOD 识别可以拦截陌生样本 | 外观缺陷检测、表面异常检测 |
| ONNX 支持 | 模型导入导出更省事 | 和外部训练框架联调 |
| 3D 匹配 | 匹配稳定性和速度都有改善 | 3D 抓取定位、深框散料抓取 |
| ARM 64 位支持扩展 | 可以在更多嵌入式板卡上跑 | 边缘计算、一体化设备 |
| HDevelop 开发体验 | 代码补全和性能分析更顺手 | 日常开发调试 |
表格列的是判断方向,真正要说的是底层逻辑:22.05 的更新重点不再只是“单个算子的功能变多”,而是整个运行时的调度能力、深度学习推理链路、跨平台部署能力在变强。这意味着你升级以后,即使把脚本原封不动跑一遍,也可能会发现速度变化了,因为底层调度策略不一样了。
2. 环境搭建和许可:20分钟从下载到跑通
2.1 不同许可模式怎么选,别等装完再后悔
HALCON 的许可是我见过最容易让人困惑的部分。简单说,开发阶段你需要一个带 HDevelop 和所有开发工具的开发许可;部署到产线时,现场电脑上装的是运行时许可,只负责执行你已经写好的脚本或编译好的程序,不允许打开 HDevelop 开发环境。
如果你用的是订阅式 Progress 授权,一般会包含开发环境的使用权,同时会给你一套运行时分发机制。这里有个非常容易踩的坑:运行时许可和开发许可不是同一个文件,现场电脑如果只拷了主程序过去,忘了装运行时许可,程序启动时会直接报许可证错误。我在项目里处理过好几次这种问题,现场工程师拍了张模糊的报错截图问我“程序是不是坏了”,实际上就是许可没配。
建议的安装顺序是:先装主程序,再装对应版本的许可管理工具,然后在许可管理工具里导入官方发给你的许可文件。导入完成以后,用 HDevelop 随便跑一个read_image就能验证许可是否生效。
2.2 工控机的配置建议
22.05 在传统算子这块对 CPU 多核调度优化得很明显,所以工控机别只看主频,核心数更重要。我常用的配置方向是:
- CPU 至少 6 核以上,带 AVX2 指令集
- 内存 16G 起步,做深度学习训练或处理大图建议 32G
- 固态硬盘必须,图像数据读写速度直接影响整个节拍
- 如果跑深度学习推理,优先考虑一张支持 FP16 的 GPU;如果只是传统 2D 定位测量,核显都够用
2.3 与 C#、C++ 和 Python 的第一次握手
22.05 的安装包里自带各语言的接口。以 C# 为例,项目里引用 HalconDotNet 之后,最简单的读取图像和阈值分割是这样:
using HalconDotNet; HDevelopExport hdev = new HDevelopExport(); HImage image = new HImage("test.png"); HRegion region = image.Threshold(80.0, 200.0);C++ 的路径也类似,引入 HALCONCpp 头文件,链接对应库。Python 的话,22.05 提供了独立的 Python 接口,安装后可以直接这样写:
import halcon as ha image = ha.read_image("test.png") gray = ha.rgb1_to_gray(image) region = ha.threshold(gray, 80, 200)这里有个新手常见报错:运行 C# 程序时提示HalconDotNet程序集找不到,或者 C++ 报HALCONCpp.dll 无法加载。原因基本就两个:一是没把 HALCON 的bin目录加入系统 PATH,二是没在项目里把对应 DLL 设为复制到输出目录。先把 PATH 配好,再检查 Debug/Release 模式下引用的位数和本机是否一致。
3. 高频算子实战笔记:会调参才算入门
3.1 从图像到区域:预处理算子的组合套路
HALCON 给人的第一印象是算子多,但实际项目里用到的高频组合其实非常固定。我的常规套路是:读图、转灰度、去噪、阈值分割、连通域、按特征筛选。
下面这段 HDevelop 代码是典型的定位前预处理:
read_image (Image, 'part.png') rgb1_to_gray (Image, GrayImage) median_image (GrayImage, MedianImage, 'circle', 3, 255) threshold (MedianImage, Region, 80, 200) connection (Region, ConnectedRegions) select_shape (ConnectedRegions, SelectedRegions, ['area','circularity'], 'and', [500, 0.5], [99999, 1.0])median_image这一步很多人会省略,但如果现场图像有轻微噪点,省略它可能导致后续阈值分割出来的区域边缘毛刺很重。select_shape一次可以筛选多个特征,'and'表示全部满足才保留,比多次 select 更高效。
3.2 模板匹配:find_shape_model 的参数玄机
模板匹配是定位工序的核心。create_shape_model和find_shape_model的参数网上到处都有,我重点讲讲被忽略的调参逻辑。
create_shape_model (ModelImage, 'auto', -10, 20, 'auto', 'auto', 'ignore_local_polarity', 5, ModelID) find_shape_model (SearchImage, ModelID, -10, 20, 0.6, 1, 0.5, 'least_squares', 0, 0, Row, Column, Angle, Score)几个参数我的理解是这样的:
- AngleStart 和 AngleExtent:不是越大越好。你把搜索角度范围拉得太大,匹配时间会涨,误匹配概率也会涨。只给实际可能出现的角度范围就行。
- MinScore:建议从 0.5 起步。设太高,实际产品被遮挡或者光照波动一点就会找不到;设太低,误匹配一堆。
- Greediness:这个参数是贪婪搜索程度,取值 0 到 1。越高越快但越容易漏匹配。我的习惯是先设 0.5,线上提速遇到瓶颈再往 0.7、0.8 调,但必须用一批现场图做回归验证。
有一次我在一个识别项目中把 Greediness 调到 0.9,单次匹配速度确实快了很多,结果夜班光照一变,整线开始频繁报警找不到目标。最后退回 0.7,把候选区域用 ROI 裁剪收小,速度不降反升,稳定性也回来了。
3.3 测量与读取:measure_pos 和 1D 测量
测量类需求同样高频。HALCON 的测量是沿着测量矩形内的灰度剖面找边缘,需要先创建测量对象,再执行测量算子:
gen_measure_rectangle2 (Row, Column, Phi, Length1, Length2, Width, Height, 'nearest_neighbor', MeasureHandle) measure_pos (Image, MeasureHandle, 1, 30, 'all', 'all', RowEdge, ColumnEdge, Amplitude, Distance)这里的小技巧是'nearest_neighbor'插值方式和measure_pos里的边缘阈值参数。边缘阈值设太低会把细小划痕也当成边缘,设太高则可能漏掉真正的边缘。我自己一般先让程序输出Amplitude(边缘幅度),统计一批正常产品的幅度分布,然后取最小值的 50% 左右作为阈值。
4. 深度学习模块的使用心得:从训练到推理
4.1 22.05的DL能力边界
很多人一听到 HALCON 的深度学习,第一反应是“工业软件做 DL 是不是噱头”。实际用过之后我的结论是:在工业视觉的窄场景里,它比通用深度学习框架更省事,因为它把数据标注、训练、验证、导出、运行时的链路都串在了一起,而且和传统算子在同一个环境下混用非常自然。
22.05 里我用得最多的是两类模型:一类是分割模型,用于像素级缺陷分割;另一类是异常检测模型,用于只知道“好品长什么样”,但不知道“坏品具体有哪些形态”的场景。后者特别适合表面划痕、脏污这类难以穷举缺陷类型的项目。
4.2 我的训练流程与参数选择
我踩过数据不足、训练发散、推理奇慢各种坑之后,总结出的流程是:
- 采集现场代表性图片,尽量覆盖不同光照、不同角度、不同批次。
- 在标注工具里做像素级标注,注意正负样本均衡。
- 创建模型,设置输入尺寸和类别数。
- 训练,监控精度和损失。
- 用独立的验证集做测试,不看训练集。
- 导出为推理格式,集成到产线程序。
参数上,我通常从一组相对保守的数值开始:batch_size取 4 或 8,epochs先跑 50,学习率从 1e-4 起步,当验证精度不再上升时再降到 5e-5。有个参数大家容易忽略,就是输入图像尺寸。HALCON 深度学习模型一般要求固定输入尺寸,你把原图直接塞进去往往不行,得先缩放或裁剪。
这里切记:用于训练的图片预处理要和推理时保持一致。我在一个项目里训练时用了带缩放的预处理,推理时在 C# 侧忘了做同样的缩放,结果模型输出的掩膜整体偏移,排查了两个小时才发现。
4.3 推理部署和常见坑
模型训练完以后可以导出,然后在 C# 或 C++ 里加载。推理本身的算子不难,关键在资源管理。每张图都重新加载模型显然不行,合理做法是启动时加载一次,之后循环推理。内存方面,几个百兆级模型同时加载会让工控机吃不消,生产项目里应该只加载当前工位需要的模型。
还有一个坑是推理时间不稳定。HALCON 的 DL 推理偶尔会因为 GPU 动态降频、显存碎片等原因抖动。我的处理是给推理环节设置超时和重试机制,连续两次超时才判定为NG,避免偶发抖动导致误杀良品。
5. 性能优化实测:从40毫秒到15毫秒的调整过程
5.1 先量化:HDevelop性能分析怎么看
不要凭感觉优化。HDevelop 里打开性能分析工具,跑一整套流程,它会按算子累计耗时排序。我最常用的操作是看每个算子累计耗时占比,先把占比最高的前三个算子找出来。
有一次我优化一个定位流程,看到耗时主力竟然是read_image加图像格式转换,而不是匹配算子,这和我最初猜测完全不同。很多项目死活跟不上节拍,不是算法不够快,而是图像数据从采集到交给 HALCON 的路径太慢。
5.2 ROI策略和金字塔是保命项
优化匹配最有效的一招是缩小搜索区域。全图匹配和只在目标可能出现的 ROI 内匹配,速度差几倍很正常。我的习惯是先用一个粗定位手段找到目标的大概位置,再在这个位置周围生成一个带余量的矩形 ROI,在 ROI 内做精确匹配。
金字塔层数同样关键。create_shape_model的NumLevels设成'auto'通常没问题,但你要知道层数越多,搜索越快,可越小的目标在高层金字塔里越容易被忽略。现场遇到“小目标找不到”时,不要无脑提高层数,先把 ROI 缩到最小,再逐层验证。
5.3 自动并行和GPU怎么用
22.05 的自动算子并行化,对多核处理器的利用比旧版好很多。传统算子层面,我建议打开自动并行:
set_system ('parallelize_operators', 'true')这个开关可以放在脚本开头,让支持并行的算子自动利用多核。注意它不是万能的,某些算子内部依赖顺序执行,强行并行反而引入额外调度开销。打开以后要实际跑数据对比。
深度学习推理则要关注 GPU 是否真的被调用。我见过一个项目,程序跑在带 GPU 的工控机上,但推理时间一直没降下来,查了半天发现 HALCON 默认还在用 CPU 跑,需要显式配置设备。
5.4 语言集成场景下的额外开销
用 C# 调 HALCON 时,有一个很容易被忽略的开销——图像数据在 HALCON 对象和 .NET 数组之间来回转换。每次ToBitmap或者从Bitmap构造HImage都会产生一次完整的内存拷贝。高频循环里这个开销极其可观。
我优化过一个外观检测程序,原代码每帧图像做一次HImage转Bitmap再转自定义格式,这里就吃掉了 5 毫秒。改成直接访问 HALCON 的图像指针或减少转换次数后,单帧总耗时下降了接近 20%。
6. 两个印象最深的排查案例与处理方法
6.1 灰度波动导致模板匹配偶尔失手
这是一个让我印象深刻的现场问题。某条产线白天良率 99.5%,到了傍晚降到 95%,时不时丢几个产品。现场换了光源、擦了镜头都没用。我拿了一批白天和傍晚的图像,对比区域内的灰度分布,发现傍晚图像整体灰度下降了约 20%,局部对比度也变软了。
排查的思路是逐层排除:图像采集硬件没问题,光照时序没问题,那问题就在匹配算法对灰度变化的鲁棒性上。我试了find_ncc_model,它对线性光照变化更稳,但遇上局部反光还是会漂。最后方案是组合拳:模板库增加傍晚光照的样本,匹配前增加一次直方图拉伸预处理,再给匹配结果加一帧时序滤波。三个动作叠加,问题才彻底压下去。
这个案例的价值不是某个参数调整,而是排查链路:先量化问题,再对比样本,最后分层解决,而不是上来就改匹配参数。
6.2 多线程共享HALCON对象引发的崩溃
另一个案例是我的老毛病。当时为了让程序处理多个相机,我在多线程里直接共享了同一个 HALCON 图像对象和模型句柄。结果运行十几分钟不定时崩溃,报错信息还不一致,特别难查。
排查下来,根子在于 HALCON 的对象引用计数不是所有场景下都是线程安全的,多个线程同时读写同一个HObject或模型句柄,会让底层引用计数混乱。修复方式很粗暴也很有效:每个线程独立加载模型副本,图像对象在线程内部创建和释放;通讯环节用队列传递,不在 HALCON 对象层面做共享。
后来我给自己定了一条规矩:跨线程传 HObject 一律不行,跨线程传图像路径、字节数组、结果数据才行。遵守这条规矩之后,多相机项目再没出过这类崩溃。
7. 把这些笔记落到日常工程习惯里
最后分享几个我做了很久的工程习惯,都是被现场问题“教育”出来的。
第一个习惯是锁定版本。只要项目上了产线,HALCON 版本就锁死,不要随手升级。22.05 我是在自测环境里充分验证后,才逐步迁移到新项目上的。旧项目不折腾,新项目用新版,这是最稳的策略。
第二个习惯是脚本结构化。HDevelop 脚本不是一次写完就扔的东西。我会把预处理、匹配、测量分成独立的过程,每个过程单独用一组图片验证。这样线上出问题的时候,能快速定位是哪个环节变了,而不是整段脚本从头查到尾。
第三个习惯是保存现场图像。所有 NG 图像按时间戳存盘,它是排查问题的重要资产。很多棘手问题都是靠回放当时现场的图像才找到根因的。
这套笔记我会持续更新。你现在手里的项目和 22.05 遇到的任何奇怪报错,都欢迎在评论区发出来,我后面会挑典型问题接着写。