ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

HALCON深度学习目标检测:工业表面缺陷检测训练部署与调参

HALCON深度学习目标检测:工业表面缺陷检测训练部署与调参 简介面向工业机器视觉从业者与HALCON深度学习入门者的目标检测实践资料围绕缺陷标注、数据预处理、模型训练与推理部署展开适合需要把检测能力落地到项目的工程师参考。包含1个docx文档压缩后约6.92MB以图文形式组织便于按流程对照阅读已有879人学习下载在HALCON深度学习方向具有一定关注度。内容从使用MVTec深度学习标注工具新建项目、设定缺陷类别、完成标注并导出数据集讲起随后梳理数据预处理的参数调整、模型训练中的配置要点以及推理阶段对新图片的检测效果对比。最后延伸到将推理结果导出的C#或C封装文件接入现有项目形成从样本到部署的闭环。整体侧重工程落地与步骤衔接能帮助读者理解HALCON目标检测各阶段的作用、参数含义与操作顺序减少自行摸索成本。1. 工业产线上把 HALCON 深度学习目标检测用起来做表面缺陷的同行大多经历过这个场面样机上用 halcon 模板匹配加 blob 分析跑到 99%换一批料、换一个班次的光源阈值就得重调一遍维护成本全压在调参上。HALCON 深度学习目标检测要解决的就是这件事——把长什么样算缺陷从人手写的阈值换成网络从标注里学出来的边界框回归直接输出 bbox、类别和置信度。它适合两类人已经在用 HALCON 做视觉、不想再引一套 Python 训练栈的工程师以及写 C#、Qt 上位机、需要把模型嵌进已有产线软件的开发者。下面按选型、训练、部署、调参四段把这条路走通。2. HALCON 深度学习工具与目标检测任务的选型2.1 分类、检测、分割、异常检测的边界在哪HALCON 的深度学习算子族按任务分成四条线选错了后面全是无用功。判断方法很简单缺陷的位置和尺寸要不要报给下游。任务典型算子入口输出什么时候用分类read_dl_classifier整图标签 置信度只判 OK/NG不关心缺陷在哪目标检测read_dl_model detection 模型多个 bbox 类别 置信度一张图可能有多个缺陷要坐标语义分割read_dl_model segmentation 模型像素级掩膜缺陷边界要贴边、要算面积异常检测read_dl_model anomaly 模型异常分数图缺陷样本极少、只有良品图产线上最常见的误判是把分类当检测用。分类网络给的是整图置信度一旦图里同时有划痕和脏污它只能给你一个混合结果后面的分拣机构没法执行。反过来如果只需要这个料要不要剔掉上目标检测是浪费——标注成本翻几倍推理也慢。2.2 预训练检测模型和骨干网络怎么挑HALCON 深度学习工具自带一批预训练检测模型命名上通常带pretrained_dl_detection_enhanced_前缀后面跟骨干网络标识。选型时看三个维度而不是看谁的精度榜单高。第一是骨干容量。轻量骨干在 CPU 上也能跑适合节拍 200ms 以内、缺陷特征明显比如大面积脏污的场景容量大的骨干对小目标更友好但显存和耗时都上去通常要配 GPU。我一般先在样机上用轻量骨干跑一版基线看看漏检集中在哪些尺寸的缺陷上再决定要不要换。第二是输入分辨率。检测网络的下采样倍率决定了理论最小可检目标一般来说网络总下采样 32 倍时输入 640 能稳定检出的目标边长大约在 20 像素以上。低于这个尺寸的划痕靠调参救不回来只能提分辨率或者改拍法。第三是类别数。HALCON 检测模型的class_ids要求从 0 开始连续编号class_names与之一一对应顺序错了训练不会报错但推理结果的类别会整体错位这种坑在联调阶段才发现最费时间。2.3 标注格式与 DLDataset 的目录结构HALCON 训练读取的数据集推荐用 MVTec Deep Learning Tool 导出本质是一个 COCO 风格的 json 加一个图片目录dl_dataset/ ├── annotations.json # COCO 格式标注images / annotations / categories └── images/ ├── part_0001.png ├── part_0002.png └── ...annotations.json里categories的 id 必须和后面set_dl_model_param设的class_ids对得上annotations里每条框是[x, y, width, height]的左上角加宽高格式不是左上右下。手工拼 json 时最容易在这里出错导出的框会整体偏移或缩放。提示标注阶段就把类别命名固定下来改名意味着重新导出数据集和重训不要等到部署阶段再统一命名。3. 在 HALCON 深度学习工具里训出第一个目标检测模型3.1 HALCON 安装与深度学习 license 检查HALCON 深度学习算子需要对应的 license 授权普通视觉 license 能读写模型文件但执行训练和推理时会报授权不足。HALCON 安装完成后HALCON 深度学习工具是单独安装的安装包里通常叫 Deep Learning Tool它负责标注和数据集管理训练本身还是在 HDevelop 里跑。先确认设备可用性这一段建议在写训练脚本之前单独跑一次* 查询当前 license 下可用的计算设备 query_available_dl_devices ([runtime, gpu], [id, name], DLDeviceHandles) * 返回空元组说明当前只有 CPU 可用后面训练要把 batch_size 压到 1~2 dev_display_devices : |DLDeviceHandles|query_available_dl_devices的第一个参数是过滤条件[runtime,gpu]表示只要 GPU 设备第二个参数指定返回哪些属性。返回的句柄数组长度就是可用设备数为 0 时说明要么没装驱动、要么 license 不含 GPU 推理此时训练耗时可能相差一个数量级得先决定是在本机慢跑还是换机器。3.2 用 MVTec Deep Learning Tool 标注并导出数据集标注环节只有两条硬规则框要贴着目标的外接矩形不要留大边距同一位置反复出现的缺陷要么都标要么都不标。第二条经常被忽略——如果 100 张图里只有 30 张标了脏污网络会学到脏污是噪声召回率会非常难看。导出时选择 COCO 格式图片建议统一缩放或裁切成与网络输入接近的长宽比避免训练时被强行拉伸。如果原图是 2448×2048 的大图、缺陷只有几十像素直接在原图上训练会被下采样吃掉正确做法是切图后再标或者用更高输入分辨率。3.3 HDevelop 训练脚本逐段拆解下面这段是从读模型到训练结束的完整链路可以整段粘进 HDevelop 改路径运行。* 1. 读取预训练检测模型模型文件随深度学习工具一起安装 read_dl_model (pretrained_dl_detection_enhanced_alexnet.hdl, DLModelHandle) * 2. 指定计算设备有 GPU 用 GPU没有就退回 CPU query_available_dl_devices ([runtime, gpu], [id, name], DLDeviceHandles) if (|DLDeviceHandles| 0) set_dl_model_param (DLModelHandle, device, DLDeviceHandles[0]) else set_dl_model_param (DLModelHandle, runtime, cpu) endif * 3. 类别定义id 从 0 开始连续和 annotations.json 的 categories 对齐 set_dl_model_param (DLModelHandle, class_ids, [0, 1, 2]) set_dl_model_param (DLModelHandle, class_names, [scratch, stain, missing]) * 4. 网络输入尺寸全流程必须与标注时的缩放策略一致 set_dl_model_param (DLModelHandle, image_width, 640) set_dl_model_param (DLModelHandle, image_height, 640) set_dl_model_param (DLModelHandle, image_num_channels, 3) * 5. 批大小与推理期阈值 set_dl_model_param (DLModelHandle, batch_size, 2) * 6. 读数据集并按 80/10/10 划分固定种子保证每次划分一致 read_dl_dataset_from_coco (dl_dataset/annotations.json, dl_dataset/images, [], [], DLDataset) split_dl_dataset (DLDataset, 80, 10, []) * 7. 生成预处理参数训练与推理共用同一份 create_dl_preprocess_param_from_model (DLModelHandle, false, full_domain, [], [], [], DLPreprocessParam) * 8. 训练超参epoch 数、是否显示进度、随机种子 create_dl_train_param (DLModelHandle, 20, true, 42, true, [], [], [], [], false, [], [], TrainParam) train_dl_model (DLDataset, DLModelHandle, TrainParam, 0, TrainEvaluation, TrainInfo)几个参数的作用值得单独说。image_width和image_height一旦设定训练样本会被缩放到这个尺寸推理时也必须用同一组值否则检测框会整体比例失调。split_dl_dataset的 80/10/10 是训练/验证/测试比例第三个数是测试集占比剩下的自动归训练集。create_dl_preprocess_param_from_model的第二个参数控制是否转灰度第三个参数full_domain表示按图像实际取值范围做归一化——如果训练图是 8 位而现场相机是 12 位这里选错会导致推理时输入分布和训练完全不一致表现为训练准确率很高现场全是误报。create_dl_train_param里的 epoch 数建议从 20 起步。20 轮之后如果验证集指标还在涨再加到 40、60如果第 5 轮就平了说明模型容量不够或者标注质量有问题加轮数没用。3.4 训练日志与评估指标怎么读训练结束后用evaluate_dl_model跑一次完整评估返回的字典里通常能看到 mAP、各类的 precision 和 recallevaluate_dl_model (DLDataset, DLModelHandle, split, [train,validation], [], EvaluationResult) get_dict_tuple (EvaluationResult, mean_iou, MeanIoU)看指标的顺序是先看训练集和验证集的 mAP 差距。差距在 5 个点以内说明没怎么过拟合训练集 0.95、验证集 0.6那是标注不一致或者样本太少。再看每个类别的 recall某一类特别低通常是样本量不够或者这类目标的尺寸小于网络能分辨的极限。最后才看 precisionprecision 低但 recall 高是阈值问题调min_confidence就能救不用重训。注意具体的指标键名在不同 HALCON 版本里略有差异用get_dict_param打印一下结果字典的键列表以本机实际输出为准。4. 推理部署从 HDevelop 到 C# 与 Qt 调用4.1 模型文件与预处理参数的一致性推理阶段的第一原则是训练用了什么分辨率、什么预处理推理就必须复现。所以不要手写image_width而是把训练时的DLPreprocessParam保存或重建出来推理和训练共用。模型文件本身是一个.hdl可以直接拷贝到部署机器的任意路径不依赖训练机。推理期要改的只有三个参数batch_size改成 1min_confidence按现场误报率调max_num_detections按单图最大缺陷数设。改batch_size用set_dl_model_param注意它和训练期不同推理改成 1 不会影响精度只是每张图单独前向。4.2 C# HALCONDotNet 推理最小闭环C# 项目里引halcondotnet.dll一个可用的推理封装大致是这样using HalconDotNet; public class DefectDetector { private HTuple _model; private HTuple _preprocessParam; public void Load(string modelPath) { // 读模型推理阶段批大小固定为 1 HOperatorSet.ReadDlModel(modelPath, out _model); HOperatorSet.SetDlModelParam(_model, batch_size, 1); // 重建与训练一致的预处理参数这一步不能省 HOperatorSet.CreateDlPreprocessParamFromModel( _model, false, full_domain, new HTuple(), new HTuple(), new HTuple(), out _preprocessParam); } public void Infer(HObject image, out HTuple row1, out HTuple col1, out HTuple row2, out HTuple col2, out HTuple classIds, out HTuple confidences) { HTuple batch, result; HOperatorSet.GenDlSamplesFromImages(image, out batch); HOperatorSet.PreprocessDlSamples(batch, _preprocessParam, out batch); HOperatorSet.ApplyDlModel(_model, batch, new HTuple(), out result); // 结果字典里每个检测框是一组等长数组按下标一一对应 HOperatorSet.GetDictTuple(result, bbox_row1, out row1); HOperatorSet.GetDictTuple(result, bbox_col1, out col1); HOperatorSet.GetDictTuple(result, bbox_row2, out row2); HOperatorSet.GetDictTuple(result, bbox_col2, out col2); HOperatorSet.GetDictTuple(result, bbox_class_id, out classIds); HOperatorSet.GetDictTuple(result, bbox_confidence, out confidences); } }GenDlSamplesFromImages把单张 HObject 包成模型要求的样本字典PreprocessDlSamples按预处理参数做缩放和归一化ApplyDlModel才是真正的前向。三个函数的输出都用同一个batch变量接是 HALCON 里常见的原地更新写法。结果字典返回的是并行数组第 i 个框的行列坐标分别取row1[i]、col1[i]等类别和置信度同理画框时按下标循环即可。4.3 Qt 调用 HALCON 的三种接入方式Qt 工程接 HALCON 有三条路选哪条取决于你能改多少代码。第一条是 C 直接调 HALCON 库。把HalconCpp.h加进工程.pro里补上头文件和库路径#include HalconCpp.h using namespace HalconCpp; void Detector::load(const QString modelPath) { ReadDlModel(modelPath.toStdString().c_str(), model_); SetDlModelParam(model_, batch_size, 1); CreateDlPreprocessParamFromModel(model_, false, full_domain, HTuple(), HTuple(), HTuple(), preprocessParam_); } HTuple Detector::infer(const HImage img) { HTuple batch, result; GenDlSamplesFromImages(img, batch); PreprocessDlSamples(batch, preprocessParam_, batch); ApplyDlModel(model_, batch, HTuple(), result); return result; }# Qt .pro 需要补充的链接配置示例 INCLUDEPATH $$(HALCONROOT)/include INCLUDEPATH $$(HALCONROOT)/include/halconcpp LIBS -L$$(HALCONROOT)/lib/$$(HALCONARCH) -lhalconcpp第二条是 HDevEngine把 HDevelop 过程导出成.hdevQt 侧只负责传图和取结果算法改动不用重编译上位机。适合视觉工程师和软件工程师分工的场景。第三条是独立进程调用算法侧编译成一个可执行文件Qt 用进程间通信传图隔离性最好代价是多一次图像序列化。条码、尺寸这类传统功能继续用 halcon 测量和模板匹配算子检测出来的框再做二次判定比纯网络结果稳。4.4 推理期三个必调参数参数含义建议起点调大后的影响min_confidence结果置信度下限0.3调高减少误报同时漏检变多max_overlapNMS 重叠阈值0.4调高会保留更多重叠框同一目标可能出多个框max_num_detections单图最大框数100设太小会丢掉边缘的小目标现场联调的顺序是先固定max_overlap和max_num_detections只动min_confidence把误报压到可接受的水平如果发现同一个缺陷反复出两个框再降max_overlap。这三个参数都能在推理阶段用set_dl_model_param改不需要重训模型。5. 小目标漏检与误报HALCON 目标检测的收尾技巧5.1 提高输入分辨率前先算显存账小目标检测最常见的解法是把image_width和image_height从 640 提到 1024 甚至 1280。收益确实明显但代价是显存和耗时按面积增长640 到 1280 是四倍像素训练阶段batch_size往往要从 4 降到 1。我的做法是先用 640 训一版把漏检样本导出统计漏检框的边长分布。如果集中在 10 到 20 像素优先考虑改拍法——换镜头、缩短工作距离、把大图切成小图——而不是硬提分辨率。切图还有个额外好处同样的网络输入尺寸下缺陷占的像素比例更大。5.2 置信度阈值与 NMS 阈值的联动这两个参数不能独立调。比如把min_confidence从 0.3 提到 0.6表面上看误报少了但那些原本靠多条低置信度框叠加才能过 NMS 的小目标会直接消失。我在现场的做法是画两条曲线一条是阈值和误报数的关系一条是阈值和漏检数的关系取两条线的交点附近作为工作点再根据产线对误报和漏检的容忍度往左或往右偏一点。这个测试用验证集跑一遍脚本就能出不需要重新标数据。5.3 用传统算子兜底深度学习模型的输出是概率不是确定性的几何关系。产线上总有一些场景更适合用传统方法位置固定的字符、边缘清晰的金属件轮廓、尺寸公差判定。把这些交给 halcon 测量和模板匹配把光照波动大、形态多变的表面缺陷交给检测网络两条链路并行最后做一次结果融合。我在实际项目里的经验是这种混合方案的现场稳定性明显好过把所有判断都压给一个网络。推理链路的验证也有个具体技巧拿一批已经跑过产线的图离线跑一遍新模型把结果和产线记录的 NG 图片人工比对统计漏检里有多少是标注本身就漏了的。如果是标注漏说明数据集要补再调参也没用。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进