首页
/
行业洞察
/
正文
INDUSTRY INSIGHT · 深度
Halcon GMM像素级分类实战:从柑橘分类例程读懂传统机器视觉落地
📅 2026/10/16 18:30:39
✍️ 爱科研究院
👁 阅读 3,247
Halcon 自带例程里有一类非常好玩的 Demo就是那种“功能不大、但五脏俱全”的教学型程序classify_citrus_fruits.hdev就属于这一类。光看名字是柑橘分类但真正跑通之后会发现它把图像特征提取、GMM 分类器训练、像素级推理、结果后处理这一整条视觉流程都串起来了。我当年第一次接触这个例程最大的感受是原来“分类”不只是把整张图扔给深度学习模型而是可以通过传统的概率模型在像素级别上把果实、叶子、背景精确分开而且整个模型只有几 KB。这篇就从这个例程出发把 GMM 分类模型在 Halcon 里怎么落地这件事彻底聊透。适合刚接触 Halcon 的视觉工程师、做农产品分选设备的开发者以及所有想搞懂“传统机器学习分类器如何在机器视觉项目里发挥作用”的朋友。读完你可以直接把这套流程迁移到自己的项目里替换数据就能用。1. 例程解读一个柑橘分类 Demo 背后的完整任务链1.1 这个例程到底在解决什么问题classify_citrus_fruits.hdev表面上就是“对柑橘图像做分类”但如果你只把它当成一个简单的图像分割例程那就浪费了。它真正做的事情是对图像中的每一个像素点进行类别判断哪些像素属于柑橘果实、哪些属于枝叶哪些又属于背景。这和我们平时说的“目标分类”不太一样。目标分类通常是先框出目标再判断这个框里是什么而这个例程做的是语义级别的密集预测输出结果更像一张“标签图”——每个像素被贴上类别标签。这种能力在工业产线上非常常见比如水果分选、表面缺陷检测、农业植株表型分析本质上都是在像素级区分“什么是什么”。例程里用的分类器是 GMM全称 Gaussian Mixture Model中文叫高斯混合模型。它通过多个高斯分布的叠加来刻画每一类图像特征的概率分布然后根据新像素落在哪个分布里来决定归属。这个思路在传统机器视觉里属于经典路线没有神经网络那种“黑盒子”的感觉训练快、解释性强尤其适合特征维度不高、场景相对固定的工业视觉任务。1.2 从图像到模型的完整数据流整个例程的运行逻辑可以拆成五个环节读图与预处理、样本采集、分类器创建、模型训练、分类推理与后处理。读图与预处理阶段Halcon 会先读取一张或一组柑橘图像通常会先做一个简单的阈值分割把前景和背景粗略分开减少不必要的计算量。样本采集阶段程序会读取一张“带标注的类别图”这张图告诉你图像里哪个区域属于类别 1、哪个区域属于类别 2、哪个区域属于类别 3然后用add_samples_image_class_gmm将像素特征和标签一起送入分类器。分类器创建阶段例程会调用create_class_gmm设置类别数、特征维度、混合分量数量这几个关键参数。训练阶段调用train_class_gmm让模型迭代收敛同时输出训练误差方便判断模型好不好。推理阶段则是用训练好的模型对新的柑橘图像逐像素分类然后借助形态学后处理把碎小的噪声区域滤掉最终得到干净的分类结果。这五个环节就是工业视觉里几乎所有“像素分类”项目的基本骨架。你看懂了这一套往后不管遇到什么分类任务都能往这个框架里套。1.3 为什么值得把它当模板反复研究Halcon 例程成百上千但很多例程是展示单点技术比如只演示滤波、只演示标定。而classify_citrus_fruits.hdev展示的是一条完整的任务链这在学习价值上完全是另一个量级。更关键的是这个例程换数据就可以迁移。你不一定用柑橘可以把图像换成 PCB 板、食品、布料、瓷砖把类别换成“焊点/基板”“合格/缺陷”逻辑完全一样。我现在做视觉项目时有时还会打开这个例程当速查手册确认某个 GMM 算子参数怎么传。对初学者来说跑通它比看十遍文档都管用对老手来说它是一个可以反复借鉴的脚手架。2. GMM 分类原理为什么偏偏是它被选进这个例程2.1 用“人群分布”来理解高斯混合模型很多人一听到“高斯混合模型”就发怵其实它的核心思想很朴素。你看一支队伍里的人如果把身高画成直方图很多时候不会是一个匀称的钟形曲线而是有两个峰——一拨人比较高一拨人比较矮。这时候用单一的高斯分布就是那个钟形曲线去拟合效果肯定很烂但用两个高斯分布叠加起来就能很好地描述整个队伍的身高分布。GMM 就是这个思路的数学化假设每一类的数据都是由若干个高斯分布混合而成的。每个高斯分布代表这类数据里的一种“子模式”多个子模式叠加就能表达更复杂的分布形态。柑橘分类为什么需要这东西因为柑橘表面的颜色并不是均匀的。一个果子上可能有橙色、淡黄色、还有高光区域如果只用一种颜色分布去描述整个“柑橘类”误差会很大。用多个高斯分布去拟合每个高斯负责一种亮度或色调区域模型对真实世界的表达能力就上来了。2.2 EM 算法在 GMM 训练中做了什么GMM 的训练靠的是 EM 算法全称是 Expectation-Maximization。这名字听起来吓人但你可以把它理解成一个“边猜边修正”的过程。第一步是初始化随机或按一定策略设定好几个高斯分布的参数均值、协方差、权重。第二步是 E 步根据当前参数计算每个样本属于每个高斯分布的概率注意这里是“软分配”——每个样本不是只属于某一个高斯而是以不同的概率属于多个高斯。第三步是 M 步根据这些概率重新计算每个高斯的均值和协方差让所有样本在整体上的似然概率最大。然后重复 E 步和 M 步直到参数收敛。我打个比方这就像老师接手一个新班级不知道学生水平怎么分层。他先凭感觉把学生分成几个小组然后看每个人在小组里的表现再调整分组边界再评估再调整几轮下来分组就越来越合理。EM 算法干的事情就是这个。2.3 不同分类器的横向选择对比很多读者会问都 2025 年了像素分类为什么不直接上深度学习还要用 GMM这是个好问题我直接给一份对比分类器数据量要求训练速度可解释性硬件依赖适合场景GMM低几百到几千样本即可极快CPU 秒级到分钟级高可以看到每个类别的分布参数无 GPU 要求特征维度低、光照相对固定的产线KNN低但推理慢训练几乎零成本高无 GPU 要求样本少、类别边界简单的场景SVM中等较快中等核函数难解释无 GPU 要求二分类、样本量不大的场景小型 CNN高需要大量标注慢小时级起低黑盒通常需要 GPU特征复杂、场景变化大、算力充足的场景从表格就能看出来GMM 的优势在于“小数据、快上手、好解释、无硬件门槛”。柑橘分类这种任务特征就是颜色维度就几个数据量也不大GMM 是性价比非常高的选择。这不是说 GMM 比深度学习厉害而是说在合适的场景下先选简单可靠的方案才是工程上的智慧。2.4 概率输出带来的工程红利GMM 还有一个容易被忽略的优点它天然输出概率而不只是硬分类标签。当你用classify_image_class_gmm对像素分类时除了得到类别标签还能得到一个置信度值表示这个像素属于该类别的概率有多大。这个概率输出在工业项目里太有用了。比如产线上你对分类结果不完全放心可以加一个阈值置信度低于 0.8 的像素一律视为“不确定区域”交给人工复检而不是让设备强行给出一个答案。这种设计能显著降低误判率是深度学习模型需要额外做软输出处理才能达到的效果而 GMM 一开始就自带。3. Halcon 中 GMM 例程的实操拆解3.1 前处理读图、掩膜、提取 ROI任何视觉项目的第一步都是把图像干净地拿到内存里。例程中用的是read_image这个没什么好说的。关键点在于预处理策略。由于 GMM 是逐像素分类如果整张图每个像素都送入模型计算量会非常大。Halcon 例程通常会先通过阈值分割框定“柑橘区域”只对 ROI 内的像素做分类。常见做法是先把 RGB 转为 HSV在饱和度通道上做阈值把低饱和度的背景区域直接剔除剩下的高饱和区域就是果实和叶子所在的候选区。这一步不需要很精确目的是“减负”不是“分割完成”。实操心得ROI 提取宁大勿小。很多人为了追求干净前期阈值卡得很死结果把果实边缘的弱特征像素全筛掉了后面分类器训练时样本不完整推理时边缘误判特别多。ROI 稍大一点把不确定区域都包进来让 GMM 自己去学效果往往更好。3.2 特征提取例程里到底提取了什么特征GMM 分类器本身不“看”图像它只处理特征向量。因此特征选得好不好直接决定分类上限。classify_citrus_fruits.hdev例程中使用的核心特征是颜色特征流程是先把 RGB 图像转换到 HSV 颜色空间再提取色相 H、饱和度 S、明度 V 三个通道作为三维特征向量。为什么不用 RGB因为 RGB 三个通道高度相关而且对光照变化非常敏感。你今天在车间北侧采集的样本和明天在南侧采集的样本RGB 数值会差很多但人眼看起来颜色是一样的。HSV 把色调、饱和度、亮度拆开了其中 H 通道描述的是“这是橙子色还是叶子绿色”这个本质属性对光照相对不敏感是分类柑橘这类彩色目标的核心特征。严格来说例程中并不一定只用了 HSV 三通道有些版本会叠加纹理特征或领域统计特征。但主线是“颜色为主、纹理为辅”。如果你的场景里目标和背景的颜色差异不大就需要额外提取纹理特征比如用灰度共生矩阵、高斯滤波响应、或者局部二值模式 LBP 来补充。特征维度不是越多越好多一个维度就多一份计算量也更容易触发维度灾难。3.3 创建 GMM 分类器参数逐项解析这是整个例程最核心的环节create_class_gmm的参数决定了模型的能力上限。Halcon 中这个算子大概是这样的形态create_class_gmm (NumClasses, NumDim, NumStates, NumMixtures, TrainingMode, CovarType, Normalization, RandSeed, GMMHandle)逐个说NumClasses类别数就是你要分几类。柑橘例程里通常是 3 类左右比如背景一类、叶子一类、果实一类。注意类别数从 0 开始编号Halcon 内部默认类别索引是 0 到 NumClasses-1。NumDim特征维度。例程用 HSV 三个通道那么 NumDim 就是 3。如果额外加了纹理特征就要相应增加维度。维度设置必须与实际喂入的特征向量长度一致否则会报错。NumStates状态数。这个参数初学者最容易懵。GMM 不是每个类别只用一个高斯分布而是可以有多个状态每个状态又由多个混合分量组成。NumStates 可以理解为“每个类别内部再划分的子状态数”。例程里一般取默认值比如 3 到 5具体取多少要通过实验调。NumMixtures混合分量数决定每个高斯状态由多少个单高斯叠加。这个值太小模型表达能力不足太大容易过拟合。我在实际项目中一般从 2 到 4 起步然后观察训练误差和分类效果再决定要不要往上加。TrainingMode训练模式字符串通常是training表示当前用于训练。推理时会用classification模式。这个参数后面还可以配合train_class_gmm来切换。CovarType协方差类型有spherical球形协方差、diag对角协方差、full全协方差等。球形协方差最简单假设特征的各个维度方差相同且独立对角协方差允许每个维度有不同方差但维度之间独立全协方差最灵活可以捕捉特征维度之间的相关性。柑橘例程一般用spherical或diag因为颜色特征维度少复杂协方差提升有限反而容易过拟合。Normalization归一化方式常见normalization表示训练前对特征做归一化避免某个维度的数值范围过大而主导距离计算。比如 V 通道是 0 到 255而 H 通道是 0 到 360如果不归一化模型会更重视 V 通道这是错误的。记住一个原则参数不是越大越好。GMM 的参数越多模型越灵活但需要的训练样本也越多。样本不够的时候模型会“记住”训练集而不是“学会”分类规律这就是过拟合。3.4 样本添加与训练别着急按类别喂创建好分类器之后下一步就是喂样本。在 Halcon 里样本不是一张一张图片“单独”给的而是通过add_samples_image_class_gmm把整幅图像和对应的分类标注图一次性送入分类器。具体逻辑是你需要准备一张“类别图”ClassImage这张图和原图像同尺寸每个像素的灰度值代表该像素的类别索引。比如灰度值为 0 的像素属于背景灰度值为 1 的像素属于橘子灰度值为 2 的像素属于叶子。然后调用add_samples_image_class_gmm (CitrusImage, ClassImage, GMMHandle)Halcon 会自动从 CitrusImage 中提取特征并从 ClassImage 中读取每个像素的标签把特征和标签配对后存入分类器。这个步骤看起来简单但有一个隐藏的重点训练样本的质量。踩过的坑很多人为了省事用画图工具随便画一张类别图。结果类别图边缘的颜色和实际图像边缘对不齐导致分类器学到了很多“边缘混合特征”推理时边界区域疯狂误判。正确做法是用 Halcon 的draw_region在图像上仔细框出每个类别的区域或者用已经分割好的区域直接转换确保像素级对齐。全部样本添加完成后调用train_class_gmm开始训练。训练时会输出一个误差值表示当前模型在训练集上的分类错误率。如果误差一直下不去就先别急着调参回去检查特征和标注是否靠谱。训练完成后可以调用get_confusion_matrix拿到混淆矩阵看看哪些类别之间容易互相误判。这对定位问题非常有帮助。比如你发现“叶子”和“橘子”总是混在一起说明这两个类别的颜色特征确实接近这时候单纯调 GMM 参数已经没用要换特征或增加特征。3.5 分类推理与结果可视化训练完成之后例程进入推理阶段。用classify_image_class_gmm对新的图像逐像素分类classify_image_class_gmm (CitrusImage, GMMHandle, ClassOutImage, Confidence)输出有两个一个是 ClassOutImage每个像素的灰度值表示类别索引另一个是 Confidence每个像素的置信度。得到 ClassOutImage 之后直接显示是一张灰度图看不出类别分布所以例程会做一个可叠加的伪彩色映射给每个类别分配一个颜色显示出来才能直观看到哪些区域被分成了哪类。推理完不是直接结束后面还有一个容易被忽视的后处理环节。因为像素级分类天然会产生很多“椒盐噪声”——个别像素被单独特立地分成别的类别。这时需要做形态学滤波比如opening_circle或closing_circle把孤立的碎块区域去掉。也可以用select_shape按面积过滤把面积过小的连通域删除只保留有意义的区域。实战细节置信度图千万别直接扔掉。我经常把它转成灰度图然后在产线界面里做热力图展示。操作员一眼就能看出模型哪些位置犹豫不决方便人工干预。这一步在很多 Demo 里没有但在真实项目里非常重要。4. 实际调参经验与模型部署细节4.1 样本采集的三个常见坑GMM 训练看起来简单但样本采集环节的失误是后面所有问题的根源。第一个坑是样本覆盖不足。柑橘在树上、在传送带上、在分选框里光照完全不同同一个果子向阳面和背阴面颜色差异巨大。如果你的训练样本只来自一个角度、一个光照环境模型在另一条产线上必然翻车。正确做法是分不同时间段、不同批次采集尽量覆盖现场的各类变化。第二个坑是类别不均衡。比如一类背景样本占了 90%果实样本只占 5%模型会对背景过度自信对果实样本学不充分。解决方式是在采集时有意控制每类样本的数量让各类别样本量尽量接近。Halcon 里也可以通过设置类别权重来调整但最优先的还是源头上平衡样本。第三个坑是标注粗心。就像前面说的类别图边缘没对齐是最大的坑。我见过不少项目训练时误差显示 1%一上现场就废查到最后就是标注边缘模糊导致的。标注这件事没有捷径就是慢工出细活。4.2 特征处理里的隐藏细节特征处理是 GMM 分类项目的隐形战场。首先是归一化Halcon 的create_class_gmm里可以设置normalization模式让分类器在训练前自动对特征做归一化但要注意这个归一化是在训练时计算的推理时必须保持相同的归一化参数Halcon 会自动处理这一点只要你别在推理时新建一个分类器就行。其次是 HSV 空间的特殊性。H 通道是角度值范围是 0 到 359这就带来一个经典问题0 度和 359 度在数值上差 359但实际颜色几乎一样。如果不处理这个“环状特性”模型会认为红色和橙色距离很远。Halcon 例程在这个问题上通常不会做太复杂的处理直接沿用 H 通道数值。我在项目中遇到过这种情况时会把 H 通道拆成两个分量sin(H)和cos(H)用这两个分量代替原始的 H 值从根本上解决角度环绕问题效果非常显著。再就是特征维度与协方差类型的匹配。如果你选择了full全协方差但特征维度很高协方差矩阵的参数数量会爆炸式增长训练样本稍微少一点就得不到稳定估计。一般建议特征维度不超过 10 维协方差用diag起步效果不满意再试full。4.3 模型保存、加载与版本管理训练好的 GMM 模型一定要落盘保存Halcon 的算子是write_class_gmm保存为 .gmm 文件。加载时用read_class_gmm读入。这里有一个很实际的工程建议保存模型时要把特征配置信息一起保存下来。什么意思训练时你用了 HSV 三个通道某个维度的顺序是先 H 后 S 再 V如果半年后你重新写了代码特征顺序变成了先 V 后 S 再 H加载同一个模型去推理结果就会全乱。我在项目里会在模型文件名上附带特征版本号比如gmm_citrus_v3_hsv_diag_2025.gmm确保模型和特征处理逻辑能对上。版本管理这件事在传统视觉项目里经常被忽略但它带来的灾难是巨大的。模型文件只有几 KB多保留几个版本完全不是问题。每次调参后记录下参数组合和对应的训练误差比事后靠记忆更靠谱。4.4 产线上光照漂移的防与治前面提到过GMM 对光照变化比深度学习更敏感。真实产线上光源会老化、环境光会变、相机会有白平衡漂移这些都会让训练时的特征分布产生偏移模型表现会逐步下降。我的处理策略是两条腿走路。第一条在系统设计阶段就做“光照免疫”优先选择 HSV 中的 H 通道作为主要特征对 S 和 V 通道做归一化处理减少光照对特征向量的扰动。第二条建立“模型监控机制”在产线运行时定期采集一小批新图像用当前模型和置信度阈值评估如果发现置信度普遍下降就说明分布已经发生了漂移需要重新采集样本并微调模型。经验之谈不要等模型烂到不可用再重训。一旦置信度均值比训练时低 10% 以上就立即启动再训练流程。小步快跑地维护模型比一次性大重训要稳得多。5. 常见问题排查与实用技巧5.1 模型训练误差很低新图分类却很差这个现象叫泛化不足说白了就是过拟合但原因往往不在模型参数而在特征和样本。先检查训练样本是不是只来自单一环境再检查是不是特征维度太高、混合分量太多。如果两者都没问题那就要怀疑标注质量了。排查顺序我建议这样先看混淆矩阵确定哪一类最差再看失败样本的图像特征判断是光照变化还是遮挡最后回头检查特征空间看两类样本在特征空间里是否真的可区分。如果特征空间里两类已经完全重叠那就不是 GMM 的问题换任何传统分类器都白搭得加新特征。5.2 分类结果碎片化严重像素分类的结果经常满天星。特别是在果实边缘、叶子边缘这些地方像素级特征本身就不稳定。这时后处理才是主角。我的标准操作流程是先closing_circle把细小的空洞填上再opening_circle把细小的突起去掉最后按面积筛选。结构化后处理顺序很重要反过来做效果差异很大。填洞要在去噪之前否则开运算会把大区域边缘也磨掉一圈造成分类结果比实际目标小一圈的“收缩现象”。5.3 推理速度不达标GMM 逐像素分类本质上是每个像素都要计算多个高斯分布的概率计算量不小。如果产线节拍要求高计算资源又有限有几个提速手段。第一缩小 ROI。这是最直接的只对必要的区域做分类能省一半以上时间。第二降采样。在保证分类精度前提下把图像缩小一半再推理速度提升四倍。第三减少混合分量数。NumMixtures 从 4 降到 2推理时间能缩短很多精度损失通常很小。第四如果像素级分类确实太慢改成区域级分类。先过分割得到一系列区域然后提取每个区域的特征只对区域做分类速度可以提升一个数量级代价是边缘精细度下降。5.4 一些非官方的实用技巧最后分享几个我在实战中积累的小技巧。训练 GMM 时把RandSeed随机种子固定下来。GMM 的 EM 算法依赖初始化不同初始化可能导致训练结果抖动。固定随机种子可以保证每次训练结果一致方便对比不同参数组合的效果。用classify_class_gmm替代classify_image_class_gmm做单样本测试。这个算子可以对一个区域或一个特征向量做分类不需要整张图跑一遍调试时定位问题非常快。我在写代码时会先用它验证模型基本能力再上整图推理。多利用 Halcon 自带的眼睛控件查看 ClassOutImage。把类别标签图叠加到原图上透明度调低一点就能直观看到分类边界是否贴合真实轮廓。如果边界偏了我通常会回过去微调特征或后处理参数而不是盲目增加训练样本。这个例程后续还可以扩展比如把 GMM 换成 SVM 试试效果对比或者加一个颜色校准板来计算真实的颜色特征。但无论怎么扩展classify_citrus_fruits.hdev作为入门样板的价值都在那里。先把这条链路跑顺再谈扩展你会在不知不觉中把整个传统机器视觉的分类体系打通。
📌 标签:
工业官网
设计趋势
AI 建站
SEO
获取完整报告 →
RELATED ARTICLES
推荐阅读
2026/10/16 18:30:39
机器人领域的OpenAI是谁?找了一圈发现OpenAI自己下场了
2026/10/16 18:30:39
33岁转行AI大模型:机会、学习路线与求职实战指南
2026/10/16 18:25:38
咸阳全飞秒医院医生推荐:3.0 与精准 4.0 区别及适配条件
2026/10/16 19:20:48
从模型到ONNX:Meta-Llama-3-8B_rai_1.8.0_hybrid的32层Llama架构、GQA注意力与KV缓存完整解析
2026/10/16 19:20:48
ACGAN原理深度解析:解耦生成与属性控制的隐空间机制
2026/10/16 19:20:48
多Agent协作如何重塑研发流程:从单模型硬伤到DevFlow AI实战
2026/10/16 19:20:48
OpenLoomi Chat完全教程:一句话布置复杂任务,AI自动拆解并执行
2026/10/16 19:20:48
MiniCPM-V-4.7-1B-int4高级参数清单:downsample_mode 4x/16x如何平衡细节与效率
2026/10/16 19:15:48
YOLOv10实时目标检测实战:从环境搭建到部署的完整案例
2026/10/16 0:04:49
HCIA-AI V3.5 模拟题库从零搭建:知识点标签、组卷算法与错题分析
2026/10/16 0:04:49
游戏项目Shader清理实战:静态扫描与动态验证双轨并行
2026/10/16 0:04:49
比特币白皮书深度拆解:从双重支付到共识机制的核心设计
2026/10/16 1:17:36
流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南
2026/10/16 1:17:35
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别
2026/10/16 1:17:35
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容
2026/10/16 1:17:35
我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频
2026/10/16 18:46:48
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证
2026/10/16 18:46:46
2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)