ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Halcon与YOLO目标检测结合实战:从模型导出到工业落地全流程

2026/9/29 17:04:17 拓冰建站 浏览量
Halcon与YOLO目标检测结合实战:从模型导出到工业落地全流程 写这篇东西的起因很简单最近好几个读者私信问我“Halcon里能不能跑YOLO”、“Halcon自带的目标检测够不够用”、“找圆测量这些活和YOLO到底什么关系”。这些问题背后其实是同一个困惑——Halcon这个老牌机器视觉软件和当下最火的YOLO目标检测到底怎么结合才最顺手。我做视觉项目有些年头了从早期的纯Halcon脚本到后来在Halcon工程里接深度学习模型中间踩了不少坑也整理出一套比较实用的流程。这篇文章就把我在实际项目里用Halcon做目标检测、接YOLO模型的全过程拆开讲清楚包括方案选型、模型导出、预处理、后处理、训练侧避坑以及找圆、抓边、字符识别、试卷切割这类具体场景怎么落地。不管你是刚接触Halcon的新手还是已经在用传统视觉算法、想往深度学习方向过渡的工程师这篇都能给你一份能直接参考的思路。1. 先想清楚Halcon做目标检测为什么绕不开YOLO很多从传统视觉转过来的朋友第一反应是“Halcon自己不是有深度学习模块吗为什么还要折腾YOLO”。这个想法没错但实际项目里往往不是二选一而是各干各的活。1.1 Halcon自带深度学习到底够不够用Halcon从17版开始推深度学习的几个预训练模型和推理工具像是apply_dl_model、read_dl_model这些算子配合标注工具MVTec Deep Learning Tool确实能跑分类、检测、分割。对于简单场景——比如固定光照下的零件有无判断、单一类别的位置定位——它够用而且好处是跟Halcon本身的数据类型无缝衔接不需要自己写额外代码。但它的问题也很明显。第一Halcon官方预训练模型基本以分类和检测为主模型结构相对固定自定义能力弱。第二训练流程封闭想改网络结构、想换更强的backbone、想用最新的训练技巧基本无从下手。第三生态跟不上。你自己在外面用YOLOv5、YOLOv8训好的模型Halcon原生读不进去除非转成它能认的格式——这就绕了一大圈。所以我的观点很明确Halcon适合做后处理、标定、传统几何测量和现场部署YOLO这类外部模型负责前端的目标识别与区域定位。两者配合比强行用Halcon自带DL模块做复杂检测要舒服得多。1.2 Halcon与YOLO的组合方式怎么选实际工程里Halcon和YOLO的组合方式我试过三种各有适用场景。第一种是YOLO跑在别处只把结果传给Halcon。比如YOLO在Python里推理完把检测框坐标通过文件、Socket或共享内存传给HalconHalcon拿到框再做ROI处理和测量。这种方式解耦最彻底适合检测模型需要频繁更新、Halcon工程相对稳定的场景。第二种是在Halcon进程内调用ONNX Runtime或OpenCV DNN加载导出的YOLO模型直接推理。这就省了跨进程通信延时低适合现场实时性要求高的设备。Halcon的read_dict、get_dict_tuple这些算子可以解析结果整条链路都在一个程序里。第三种是只用Halcon的深度学习推理接口强行把YOLO权重转换后塞进去。我试过非常折腾而且转换工具长期没人维护YOLOv8之后的版本基本没法转。除非是早期YOLOv3这种结构简单的模型否则不推荐。从近两年的项目看最稳的是第一种和第二种结合Halcon负责采集图像和几何量测YOLO负责定位和分类中间用ONNX Runtime做桥梁。1.3 适用场景切分给场景做个简单切分能帮大家少走弯路。如果是纯几何检测比如圆环定位、边缘抓取、曲线长度测量这类用Halcon传统算子就够了。find_circle、edges_sub_pix、fit_line_contour_xld这些算子成熟稳定精度高实时性也好没必要上YOLO。如果场景里需要“先识别再测量”比如先找到产品上的铭牌区域再测量铭牌上的字符间距或者先定位到工件再测量工件的圆孔位置——这时候YOLO负责粗定位Halcon负责精测量是黄金搭档。如果场景本身就是要做目标分类和区域检测比如检测传送带上的缺陷类别、识别图像里的多类目标——那核心工作量就在YOLO训练侧Halcon更多是做图像前处理、结果显示和与上位机通信。2. 核心链路从YOLO模型到Halcon推理聊完方案说点能直接落地的。下面这条链路是我项目里验证过很多次的从YOLO训练完到Halcon里跑起来一共四步。2.1 YOLO模型导出的关键一步ONNX在Halcon侧做YOLO推理最常用的方式是接ONNX Runtime。所以训练完YOLO后第一件事是把.pt权重导出成.onnx格式。以YOLOv8为例导出的命令很简单yolo export modelyolov8n.pt formatonnx opset12导出时注意几个参数。opset建议设在12到14之间ONNX Runtime兼容性最好simplify建议打开能去掉一些冗余运算减小模型体积。导出完成后最好用onnxruntime先验证一遍输出维度确认输入输出节点名。很多朋友会在这卡住Halcon里读ONNX模型读不了。因为Halcon原生不支持ONNX格式我们需要的是在Halcon代码里调用ONNX Runtime的动态库而不是让Halcon去“读”ONNX文件。这跟Halcon读自带DL模型完全是两个概念。我常用的做法是Qt或C写一个推理封装里面初始化Ort::Session加载模型文件然后在Halcon的C接口里直接调用这个封装。如果你不想用C还有个偏招用Halcon的execute_operator配合外部程序或者直接把推理写在Python里Halcon通过system调用Python脚本。但这种方式在工业现场部署不太靠谱每次调用都起一个Python进程速度太慢。2.2 YOLO输出预处理一半的坑都在这里YOLO模型的输入是固定尺寸的RGB图像归一化到0到1之间。而Halcon读进来的图像通常是单通道灰度图或者三通道的byte类型图像通道顺序是R/G/B但也可能是B/G/R尺寸更不可能刚好是模型要求的640×640或者1280×1280。所以推理之前必须做三件事通道转换、尺寸resize、归一化。通道转换用Halcon的trans_to_rgb或者直接compose3把三个通道合成RGB图。注意YOLO训练时用的是OpenCV读图通道顺序是BGR如果你把Halcon的RGB图直接塞进模型检测结果会明显变差。保险的方法是先decompose3拆通道再按BGR顺序compose3回来。这个细节我吃过亏——第一次接YOLOv5时发现所有类别都测不准排查半天就是通道顺序反了。尺寸resize不是简单拉伸。YOLO原版训练用了letterbox即在保持宽高比的前提下把长边缩放短边填充灰边。如果推理时直接用zoom_image_size拉伸到640×640目标会被拉变形检测精度下降。Halcon里没有现成的letterbox算子需要自己写* 假设输入图像为Image目标尺寸640x640 get_image_size(Image, Width, Height) Scale : 640.0 / max(Width, Height) NewWidth : round(Width * Scale) NewHeight : round(Height * Scale) zoom_image_size(Image, ImageZoomed, NewWidth, NewHeight, constant) * 再创建一个640x640的画布把缩放图贴到中间 gen_image_const(Canvas, byte, 640, 640) * 计算粘贴偏移 OffsetX : (640 - NewWidth) / 2 OffsetY : (640 - NewHeight) / 2 * 用reduce_domain和compose相关操作完成复制归一化比较简单convert_image_type(ImageZoomed, real)之后乘上1.0 / 255.0就行。有些同学会把归一化和通道顺序搞混记住一句话归一化是数值缩放不影响通道顺序通道顺序错了模型看到的颜色就是错的。2.3 后处理从输出张量到检测框ONNX导出的YOLO模型输出是一个三维张量形状大概是[1, 84, 8400]。其中84表示4个坐标信息加80个类别概率8400是不同尺度下anchor的数量。要从这堆数字里解析出检测框需要做置信度过滤和NMS。这一步我建议用C写不要用Halcon脚本硬算。Halcon做矩阵运算和循环效率不行8400个候选框在脚本层过滤一遍耗时可能翻好几倍。正确做法是ONNX Runtime在C层完成推理拿到输出后直接处理。NMS方面有现成的cv::dnn::NMSBoxes可用C里的OpenCV会自带DNN模块很方便。如果没有OpenCV手写一个最简单的NMS也就几十行代码按置信度从高到低排序然后逐个比较IoU大于阈值的框直接丢弃。后处理完拿到的是归一化坐标需要在Halcon里还原成像素坐标。注意前面letterbox填充的边距要在这里减掉。具体做法是先根据原图宽高和缩放比例反算再把画布偏移减掉。我见过有人忘了减偏移所有检测框整体往右下角偏了一大截找了好久才发现是letterbox的边距没处理。得到检测框后可以用Halcon的gen_rectangle1生成矩形Region再做后续的reduce_domain、裁剪、OCR或者测量。这个流程跑通之后YOLO在Halcon里就算真正落地了。3. 几个能直接参考的落地场景链路通了得看具体怎么用。下面挑几个高频场景聊都是我在实际项目里做过的。3.1 经典几何检测场景Halcon找圆和抓边靠近Halcon的老本行那就离不开找圆和抓边。这些操作和YOLO怎么配合呢举个例子检测一个圆形工件的圆心坐标和半径但工件的位置是随机摆放的图像里还有多个干扰圆。传统做法是全局find_circle或者create_shape_model做模板匹配一旦背景复杂误检率就上去了。换成“YOLO定位Halcon测量”之后YOLO先输出圆的大致RegionHalcon再在Region内部做亚像素找圆* 假设YOLO已经返回了一个检测框区域DetectionRegion reduce_domain(Image, DetectionRegion, ImageReduced) threshold(ImageReduced, Region, 0, 128) connection(Region, ConnectedRegions) select_shape_max(ConnectedRegions, SelectedRegions) * 生成亚像素轮廓 gen_contour_region_xld(SelectedRegions, Contours, border) fit_circle_contour_xld(Contours, algebraic, -1, 0, 0, 3, 2, Row, Column, Radius, StartPhi, EndPhi, PointOrder)这样得到圆心和半径都是在局部坐标系里做的精度比全局找圆稳定得多。而且测量范围被限制在YOLO给出的框里那些干扰圆自然就被排除了。抓边拟合直线也是同一个思路。传统的edges_sub_pix是全图提取边缘很容易把背景纹理当成目标边缘。先让YOLO框出目标区域再reduce_domain到区域内提取边缘最后fit_line_contour_xld拟合直线整个过程的鲁棒性会提升一大截。曲线长度测量也类似。YOLO定位到目标轮廓的大致范围后Halcon在局部提取轮廓然后用get_contour_xld或者length_xld计算长度。这套组合拳我用了很多年基本能应付大多数“先定位后测量”的场景。3.2 YOLO字符识别与试卷题目自动切割热词里有人提到了“基于YOLO的试卷题目自动切割”和“YOLO字符识别”这两个其实是同一类问题——检测文本区域再做后续识别或切分。我做过一个试卷扫描整理的活儿流程是先用YOLO检测每道题目的题号区域输出每个题号的检测框Halcon根据检测框对整张试卷图做切割把每道题保存成独立的图片。这比传统投影法切割靠谱得多因为手写试卷的排版不规整投影法经常把两题切开或者并到一起。字符识别方面纯Halcon自带OCR对印刷体还行但遇到手写体识别率就很惨。我当时是YOLO把每个字符或词条的位置框出来然后裁剪成单字符图片送进训练好的识别模型。这个思路本质上是“检测识别”两步走YOLO负责检测识别环节可以用Halcon的OCR也可以用外部的分类模型。3.3 图像写入文字与测量标注的小技巧很多现场项目需要在检测结果图上写字或者在Halcon里把测量结果显示出来。这个用Halcon的set_tposition和write_string就能完成set_tposition(WindowHandle, 50, 50) write_string(WindowHandle, Detected: ClassName)有一点值得提如果是在保存的图片上写文字而不是窗口上显示需要把窗口句柄换成gen_image_to_window相关流程或者直接把文字做成Region再叠加到图上。我见过不少同事一直在窗口上写结果保存图片时文字不见了就是因为没搞清楚write_string是写进窗口Buffer的。4. YOLO训练侧绕不开的坑与经验落地时很多问题其实出在训练环节而不是Halcon调用环节。不少同学拿着别人的模型直接接进Halcon效果不好就以为是集成出了问题其实模型本身就没训好。4.1 数据集准备与标注数据集的多样性比数量更重要。比如做鸟类目标检测光下载一个鸟类数据集是不够的现场背景、遮挡程度、光照条件都不同。我的建议是至少一半数据来自现场实拍而不是只用公开数据集。标框时要统一标准——是靠紧目标还是留边距遮住的算不算这些细节都要写进标注规范。热词里还有“中餐数据集”这种偏门的说明大家确实在尝试各种垂直场景。垂直场景数据集少不要紧可以用公开模型做预训练再拿少量实际数据微调。比如用一个通用的检测模型作为起点在几百张中餐图片上微调效果往往比从零训练好得多。4.2 损失函数、预训练模型与训练稳定性YOLO的损失函数在v5之后变成了组合Loss包含分类损失、置信度损失和边框损失边框部分用CIoU或者SIoU。很多人问“损失函数怎么调”我的经验是优先调置信度损失的权重因为它直接影响误检率。如果预测框很准但多了很多误检那置信度损失的权重可以适当加大。预训练模型下载也是个高频问题。YOLOv8官方仓库会发布在不同数据集上预训练的权重比如基于ImageNet预训练的backbone如果是从头训练backbone加载预训练权重能显著加速收敛。我的习惯是优先用官方发布的COCO预训练权重来做迁移学习而不是自己从头跑。训练过程中常见的一个异常是“BN崩溃”表现为训练loss突然暴涨或者变成NaN。这主要是因为batch size太小或者学习率初始值太大。特别是用预训练模型微调时如果整个backbone一起训学习率设在0.01以上风险很高。我一般微调时学习率从0.0001开始并且固定backbone前几层的参数等loss稳定后再逐步解冻。混淆矩阵方面YOLO训练完都会输出但很多人不太看。热词里提到“yolo混淆矩阵总合不唯一”那是因为混淆矩阵是按类别独立计算IoU匹配的有的目标同时匹配多个类别再加上背景类别各列之和当然不等于总数。不用太纠结这个重点看每类的Recall和Precision就够了。4.3 小目标检测与移动目标检测小目标检测是另一个持久战。热词里的“移动小目标检测”和“三维目标检测”都跟这个有关。做过小目标检测的朋友都懂YOLO在小目标上表现一直不如大中目标。我的经验是不要一味加大输入分辨率而是改造anchor或者用多尺度特征融合。Halcon这边配合的话可以把原图先切块再做检测每一块单独推理最后合并结果。虽然速度慢一点但小目标的召回率能明显提升。移动目标检测要关注推理速度和帧间一致性单帧检测是不够的。我在工程上用YOLO做移动目标定位时会加上简单的追踪逻辑——上一帧的检测框与当前帧做IoU匹配匹配上的框继承ID没匹配上的作为新目标。Halcon虽然没有内置追踪器但基于Region的匹配操作就能实现一个简单版本。4.4 YOLO实例分割与Transformer变体热词里提到“yolo实例分割”和“yolo和transformer结合”这些都是YOLO家族的分支。YOLOv8-seg在检测的基础上多了一个mask分支可以直接输出目标轮廓。如果项目里需要的不只是框而是轮廓区域用实例分割模型在Halcon里拿轮廓做测量会比“检测框图像分割”更准确。Transformer结合YOLO的思路目前更多应用在backbone替换上比如用Swin Transformer替换CSPDarknet。效果好但在工业相机上额外消耗大我一般只在GPU设备上启用普通的CPU现场还是老老实实用经典YOLO。多模态目标检测和开放词汇目标检测这些新方向暂时还进不了工业现场一个是推理速度不够一个是依赖外部大模型的embedding。如果只是做实验可以参考但落地上建议保持观望。5. HalconYOLO落地时的高频问题与排查记录这节整理一下我实际遇到比较多的问题也算是个速查表。5.1 环境、授权与版本兼容问题第一个绕不开的是Halcon授权。Halcon商用需要license很多公司用试用版做开发但试用的输出会有水印或者限制分辨率。如果项目要落地license该买还得买。另一个是版本问题不同版本的Halcon对深度学习的支持差别很大18版之后相关算子才比较齐全23版对ONNX Runtime集成更友好。我建议新项目直接上Halcon 23及以上旧项目做深度学习相关功能也尽快升级。“qt怎么调用halcon”也经常被问到。Halcon官方提供了HalconCpp库在Qt项目里只要在.pro文件里加上INCLUDEPATH和LIB路径然后#include halconcpp/HalconCpp.h就可以用了。注意在Release和Debug模式下要分别链接对应版本的库否则一堆LNK2019错误等着你。5.2 检测速度和精度失衡现场最常见的反馈是“YOLO检测太慢”或者“一卡一卡的”。先梳理一下瓶颈在哪里是推理本身慢还是图像采集慢还是Halcon后处理慢如果推理慢优先尝试更小的模型比如从yolov8m换到yolov8n如果图像采集慢看看相机是触发模式还是连续模式如果后处理慢把后处理从Halcon脚本搬到C层。我见过最夸张的一次客户说“检测很慢”结果发现是Halcon里的dev_display不停刷新窗口导致的显示开销去掉显示后速度直接翻倍。精度方面如果检测框明显偏移优先检查预处理。通道顺序搞反、letterbox偏移没还原、归一化忘记做三个里至少占一个。如果检测不稳定比如同一张图两次检测结果不一样检查输入图像是否真的相同——有些相机硬件增益自动变化看起来一样的图实际像素值差了几个灰度级。5.3 如何判断一个物体是否完整“Halcon怎么检测一个物体是否完整”这个搜索词很有代表性。我的做法是让YOLO先检测出物体的整体区域和每个子部件的区域然后在Halcon里计算子部件区域与整体区域的包含关系。比如检测手机是否缺少摄像头YOLO输出手机框和摄像头框Halcon判断摄像头框是否落在手机框内并且面积占比是否在合理区间。这个方法的关键在于子部件的面积阈值。面积太小一个噪点也会误判面积太大真正的缺失检测不出来。我一般选目标框面积的10%到15%作为下限具体值要对着现场数据调。汉化算子手册的问题也提一下Halcon官方只有英文手册中文社区有翻译版本但更新速度跟不上新版本。我的建议是直接看英文原版遇到不认识的算子用系统自带的help窗口查一下比依赖翻译版靠谱得多。个人体会折腾这么多年Halcon和YOLO最大的体会是不要把Halcon当深度学习框架用也不要把YOLO当万能测量工具。Halcon最擅长的是在确定“看哪里”之后做精确的几何分析YOLO最擅长的是在不确定“看哪里”之前先框出候选区域。两者天然互补硬要合二为一反而两边都不讨好。如果你正在做类似的项目我的建议很直接先花两天时间把本节2.2里的预处理流程在Halcon里跑一遍确认输出的检测框和坐标还原都没有问题再去动训练和调优。因为所有后续工作都建立在“模型推理结果能正确传回Halcon”这条链路上这条链路不通模型训得再好也白搭。最后再分享一个细节写Halcon调用外部模型时记得把图像转换和结果解析封装成独立的函数不要散落在主程序里。因为现场调试时你一定会反复改预处理参数和后处理逻辑封装好能让自己少掉一半头发。