☰
YOLO统一格式下的智慧工厂多场景视觉识别实战解析
2026/10/19 13:19:35 网站建设 项目流程

监控室的屏幕上,下午三点的料场,一团尘被风卷起来,我还没看清具体浓度,旁边的人已经在问“这算不算超标”。同一时间,装卸区的铲车斗臂抬到一半,基坑里的挖掘机正在往禁入区方向移动,磁选产线那边的除铁器吸面快满了——如果不是这一整套深度学习YOLO格式的识别体系在扛着,光是靠人盯这四块屏,早晚得崩溃。这一期讲的是我在智慧工厂视觉识别项目里的一个真实切片:扬尘识别、铲车装载识别、工程重型机械识别、磁铁识别,四个完全不同的场景,统一到同一套YOLO数据管线和部署架构里。整个过程涉及数据标注规则、模型选型、阈值策略、防误报方案和现场联动逻辑,不是教科书式的概念讲解,都是跑过真视频、挨过真告警之后沉淀下来的东西。无论你是刚接触工业视觉的新手,还是正在做类似项目的同行,照着这条路走,能少踩不少坑。

1. 四类识别任务拆开看:扬尘、装载、机械、磁铁的各自硬骨头

1.1 扬尘识别:最难的不是识别,是区分“这是尘还是雾、烟或镜头污点”

料场扬尘、装卸点扬尘、道路二次扬尘,环保监控点名要管的东西。扬尘本身在图像上并不是一个“有清晰边界”的目标。它的浓度从中心向外递减,边上可能只是淡淡一层灰雾,你让算法去学“完整尘团”,学出来的框会忽大忽小,完全没法做后续的面积占比逻辑。

我这边实际用的定义是:只标注“可见尘团的核心浓度区”,外围的淡雾一律不进框。这样一致性好很多,后续联动喷淋系统时,也只需要按核心区面积占比触发。

扬尘识别最大的干扰项是视觉相似的“三兄弟”:雾、烟、水汽。雨雾天整个画面都是灰蒙蒙的,模型很容易把整片背景判成dust。更头疼的是镜头污渍。广角枪机挂在高处,镜片上落灰、雨水残留、蜘蛛网,拍出来的模糊区域和远景尘团在低分辨率下几乎一样。后面我会单独讲怎么用背景差分和额外类别解决这个问题,这里先记住一个结论:扬尘识别项目里,真正决定成败的不是模型结构,而是“你有没有把非尘干扰物单独建模”。

1.2 铲车装载识别:识别“动作状态”比识别“对象”难一个量级

装载机(铲车)本身很好认,车体、轮胎、动臂的特征都很明显。但业务要的不是“画面里有一台铲车”,而是“这台铲车现在正在装载”还是“正在运输”还是“正在待机”。

这就是从目标检测变成动作状态识别。单帧静态图做不了这件事,因为“装载”是一个过程:铲斗插入料堆、斗臂举升、车辆倒退出堆、铲斗翻转卸料、回到低位。只看某一帧,你根本不知道这个姿态属于哪个阶段。

我的做法是分两层:第一层用YOLO检测铲车本体,拿到车的bbox之后,在车体ROI上方区域额外检测铲斗姿态,姿态分成三类——bucket_raising(举升)、bucket_dumping(翻转卸料)、bucket_low(低位)。第二层用ByteTrack跟踪每台铲车的ID,把单帧姿态输出做时序状态机判断,只有完整走完“低位→举升→卸料→低位”才算一次装载计数。

这样做的原因是工程上比端到端动作识别网络更可控。单帧姿态分类错了,时序上还有机会纠错;端到端的3D卷积网络在这种长期状态转移上反而不好调。

1.3 工程重型机械识别:尺度跨越很大的一个类别集合

挖掘机、装载机、推土机、渣土车、汽车吊,这套识别的核心价值是安全区域管控和设备利用率统计。禁入区域里出现挖掘机,系统要能告警;渣土车往基坑里倒渣土的次数,要能自动记录。

这类目标最大的问题是尺度。同一个摄像头画面里,近处一辆渣土车可能占满1/3画面,远处一台挖掘机可能只有20×20像素。YOLO的常规检测头在P3层(stride 8)上对20像素的目标已经很难输出稳定特征,更别提这类机械的颜色和背景(土方、混凝土)经常高度接近。

类别混淆也存在。轮式装载机的侧面轮廓和挖掘机在某些收臂姿态下,特征很像。我实测下来,早期版本经常把斗臂朝下的挖掘机判成loader。后面把所有俯仰角度的样本重标了一遍,才把混淆降下来。

1.4 磁铁识别:生产线最不起眼但漏报后果最重的一类

这个磁铁指的不是玩具磁铁,而是磁选机、除铁器、电磁吸盘这类用于从料流中吸走铁质杂物的设备。比如带式输送机上的悬挂式除铁器,把矿石里的铁块吸住,保护下游破碎机;再比如尾矿磁选滚筒,把精矿粉分离出来。

识别目标不是“有没有磁铁”,而是磁铁设备当前处于什么工作状态。我这边分了三个类别:

  • magnet_idle:吸面干净,没有吸附物
  • magnet_full:吸面堆满铁件,需要清理或卸料
  • magnet_discharging:正在做退磁卸料动作

别看就三类,漏报后果很严重。magnet_full持续太久没清理,铁件堆太多会掉落进料流,直接打坏下游设备;或者除铁能力下降,影响产品质量。这类场景的光照和画面条件也很差:传送带区域粉尘大、照度低、红外补光下金属反光严重,标注类别不平衡更是家常便饭。后面专门有一节讲怎么对付它。

四类任务的差异汇总如下:

任务典型摄像头位置核心业务价值主要难点
扬尘识别料棚顶部、厂区主干道、装卸点环保达标、喷淋联动半透明、雾/烟/镜头污渍干扰
铲车装载识别装卸区侧面高位装载计数、效率统计要识别动作状态,不是识别对象
重型机械识别基坑边缘、厂区制高点禁区告警、设备利用率尺度跨度大、型号差异大
磁铁识别皮带机上方、磁选平台设备保护、工艺监控低照度、类别不平衡、金属反光

2. 统一数据字典与YOLO标注体系设计

2.1 为什么四类任务必须统一成YOLO格式

很多团队做工业视觉,会按场景各搞一套标注格式:扬尘用COCO JSON,机械用VOC XML,磁铁又另起炉灶。结果就是每种格式写一套解析脚本、搞一套训练流水线,数据没法复用,人还累得半死。

YOLO格式的逻辑极其简单:一张图对应一个txt文件,每行一个目标,五个字段,分别是类别id、目标中心点归一化x坐标、中心点归一化y坐标、归一化宽度、归一化高度。所有坐标都除以图像宽高,所以无论训练时输入是640分辨率还是960分辨率,标注文件都可以原样照用——这是它在工业项目里最舒服的地方。

四个任务统一到这个格式之后,产线变得非常干净。同一个料场场景里,一台摄像头可能同时拍到铲车和扬尘,这两个目标直接写进同一个txt,不需要任何格式转换。新增类别只需要在训练配置里加一行映射,数据管线零改动。

2.2 一份能直接用于训练的数据字典

在这个项目里,我最终整理出的类别字典是这么一套:

0 dust 轻度尘团 1 heavy_dust 重度尘团 2 loader 轮式装载机本体 3 bucket_raising 铲斗举升状态 4 bucket_dumping 铲斗翻转卸料状态 5 excavator 液压挖掘机 6 bulldozer 推土机 7 dump_truck 渣土车 8 crane 汽车吊/塔吊 9 magnet_idle 除铁器吸面干净 10 magnet_full 除铁器吸面吸附已满 11 magnet_discharging 除铁器正在卸料

有两点需要在标注规则里提前说清楚。第一,loader本体框和bucket姿态框是允许重叠的。铲斗在车体上方时,姿态框会落在车体框内部,后处理做NMS时不能把它们互相抑制掉,否则姿态类别基本全废。第二,扬尘分成dust和heavy_dust,是为了让联动策略有区分度:轻尘只做记录上报,重尘才触发喷淋系统。如果你把扬尘合并成一类,后续每次调联动逻辑都很痛苦。

这段代码是检查标注文件是否合规范用的,我每个批次标注完成都会跑一遍:

import os def validate_yolo_label(txt_path, img_w, img_h, num_classes=12): bad_lines = [] with open(txt_path, 'r') as f: for line in f: parts = line.strip().split() if len(parts) != 5: bad_lines.append(line) continue cls, x, y, w, h = int(parts[0]), float(parts[1]), float(parts[2]), float(parts[3]), float(parts[4]) if cls >= num_classes: bad_lines.append(line) continue if not (0 <= x <= 1 and 0 <= y <= 1): bad_lines.append(line) continue if w <= 0 or h <= 0 or w > 1 or h > 1: bad_lines.append(line) return bad_lines

2.3 标注一致性的三个检查环节

标注环节是最容易出现“隐性脏数据”的地方,而工业数据一旦脏了,后面模型训出来你都不知道该信谁。我做了三道检查:

第一道,跨帧中心点连续性检查。同一个目标在连续帧里的bbox中心点如果跳变超过自身宽度的20%,基本可以确定某一帧的框标错了。跟踪算法能帮你把这个异常自动挑出来。

第二道,扬尘边界一致性检查。扬尘是半透明的,不同人对“尘团到哪里为止”的判断完全不一样。我要求标注员只框“核心浓度区”,并给了参考示意图。每批标注后随机抽20%做双人复核,Cohens Kappa低于0.8的样本全部回炉。

第三道,视频序列抽查。标完一个视频后,用播放模式快速过一遍,重点看状态类别的切换点是否正确。完整视频检查比单帧抽检更能发现“状态边界帧”的错误。

标注工具方面,我用x-anylabeling比较多。它支持视频抽帧、半自动跟踪,能在一定程度上减少重复标注的体力活。但就算有工具,每帧的姿态状态判断还是得靠人眼过。

3. 数据采集与样本体系:三个深坑和对应解法

3.1 雨雾天、镜头污渍、扬尘三兄弟怎么分开

误报来源分析是这套系统上线初期最主要的活。我把所有扬尘误报抓拍图拉出来,发现来源高度集中在三类:雨雾天的背景湿气、镜头上的污渍/水痕、喷淋系统自身喷出的水雾。它们的特征和真尘团在单帧图上几乎无法区分。

我用了两套手段压制误报。第一套,训练一个额外的lens_blur类别,把镜头污渍、水痕这类“静态模糊区域”建模进去。模型学到的是污渍通常固定在画面某个位置、纹理方向性强。加了这类别后,扬尘识别的F1从0.76升到0.85。

但lens_blur类别引入了新问题——有些真尘团被误判成lens_blur,导致漏报。我的处理是在后处理里给lens_blur的置信度设了一个0.4的上限,超过0.4也不当作lens_blur,而是标成unknown,由下游业务逻辑自行决定要不要触发。这样既吸收了污渍干扰,又保住了真尘团的通路。

第二套是背景差分门控。具体逻辑是:计算当前帧和背景模型之间的像素变化比例,如果变化比例极高(比如超过40%),说明画面里有快速运动的东西,比如水雾飘散、镜头被遮挡、车辆驶过。真尘团的运动速度相对慢很多,是整体漂移。通过这个门控,水雾场景的扬尘告警被有效压制。单纯靠图像分类模型去区分水雾和尘团,效果远不如这种物理判据来得可靠。

3.2 小目标:20像素的挖掘机怎么才能被识别

大范围监控场景里,远处一台挖掘机往往只有20×20像素,一个小目标在P3层的特征图里就剩3×3个格子,信息量极度不足。前期测试里,机械类别在大目标上的AP能到0.9以上,但小目标AP只有0.42。

我对比了两种方案。第一种,把输入分辨率从640提到1280。小目标AP从0.42提升到0.53,代价是推理耗时翻倍。第二种,SAHI切图推理,把大图切成1024×1024的块,重叠部分用NMS合并。这个小目标AP提升到0.68,效果最好,但耗时又翻了一倍。

最后在项目里我用的是混合方案:主路用1280输入做全图检测,保证中大型目标的实时召回;对预选出来的低置信度区域,再切小图做细粒度确认。不是所有摄像头都跑这套流程,只有安装在制高点、覆盖范围大的那几路才启用。算力分配要按摄像头的重要性来,不能一刀切。

3.3 动作边界帧:铲斗从哪一帧开始算装载

装载状态的标注,最大的争议在边界帧上。铲斗从低位开始举升,到底哪一帧算“开始举升”?两个标注员在不同帧上画框,这事特别普遍。如果训练数据里的状态标记不一致,模型学到的就是一团模糊的状态边界。

我的做法是:标注时以视频片段为单位,先把关键帧标出来,比如铲斗完全放下那一帧、举升60度那一帧、翻转卸料最大角度那一帧,然后用插值给中间帧生成标签。训练时对姿态类别做标签平滑,降低模型对边界帧的敏感度。推理侧再用滑动窗口输出状态变化事件,窗口内超过半数的帧判定为同一状态才切换。这样单帧的抖动不会直接造成一次虚假计数。

3.4 类别不平衡:磁铁状态识别为什么容易翻车

磁铁识别项目里,采集回来的数据分布长这样:magnet_idle占了85%,magnet_full占8%,magnet_discharging占7%。如果直接拿这个分布去训练,模型会倾向于把所有画面都判成idle,因为光猜idle就能拿到85%的准确率。

我的应对方案有三条。第一,对稀有类别做过采样,把full和discharging的样本复制后,在HSV空间做色相、饱和度、明度扰动,生成更多变体。第二,训练时给稀有类别的cls loss乘以权重,full乘2.5,discharging乘2.0,idle乘1.0。第三,评估不只看整体mAP,而是分别看每个类别的recall。magnet_full的recall目标定到0.9以上,因为它的业务含义是“该清理了但没清理”,漏掉一次就可能造成设备损坏。magnet_discharging的recall可以放宽到0.8,它只是过程状态,错一帧后面还能补回来。

另外,mixup这个增广在磁铁数据上要关掉。mixup会生成两张图的混合体,相当于制造出“半吸状态”的假样本,而这个状态在真实生产里根本不存在,反而把模型的边界弄糊涂了。

4. YOLO版本选型与训练策略:一个权重还是多个权重

4.1 版本实测对比:v5、v8,还有更重的变换器方案

我在同一个四类任务混合数据集上做了对比测试。统一用NVIDIA RTX 3060 12G训练,TensorRT FP16推理,结果大致如下:

方案输入分辨率推理速度整体mAP50小目标AP部署复杂度
YOLOv5s64055 FPS0.870.42低
YOLOv8s64045 FPS0.890.47低
YOLOv8s96025 FPS0.910.53低
RT-DETR64015 FPS0.920.58中

结论很直接:主力用YOLOv8s,部署用的是TensorRT导出的FP16引擎。RT-DETR精度确实最高,但这个项目里我跑不起它的延迟预算,而且工业现场的TensorRT导出和动态尺寸处理更麻烦。YOLOv9、v11这类新版本我没有选用,主要的考虑是稳定性和生态成熟度。项目的长期维护人员不一定能跟上新模型的更新节奏,一个部署形态稳定、权重转换工具链成熟、社区资料丰富的模型,才是工业现场最靠谱的选择。

小目标场景我调高输入到960;扬尘这种半透明纹理目标,用YOLOv5n加480输入就够了,因为扬尘不需要精细的形状特征,轻量模型反而更稳。

4.2 单权重还是多权重:不要为了“合一”而合一

刚开始我也想过四个任务塞进一个模型权重里,部署最简单,一个engine文件全搞定。但实测下来问题很多。

第一个问题,置信度阈值没法统一。安全告警(机械进禁区)必须用高阈值0.6以上,宁可漏一点也不要天天误报;扬尘识别却需要低阈值0.4左右,因为环保场景里漏报一次可能就要被通报。同一个后处理阈值卡谁都不合适。

第二个问题,增广策略互相打架。扬尘类目标需要低强度的mosaic,因为拼接线会破坏尘团的半透明边缘;机械小目标又需要高分辨率输入。同一个训练流程里,这两类需求只能取一个折中,两边都不讨好。

第三个问题,NMS互相干扰。扬尘框和挖掘机框挨在一起时,NMS按重合度抑制,可能把置信度偏低的机械框直接吃掉。我在后处理里给机械类别加了一个得分放大系数,但这些小修补不如直接物理隔离来得干净。

所以最终方案是两套权重:机械+装载一套,扬尘+磁铁一套。原因很实际——这两组的摄像头位置完全不同:机械和装载摄像头在装卸区、基坑;扬尘摄像头在料场和主干道;磁铁摄像头在皮带机上方。它们大概率永远不会出现在同一个画面里,硬塞进一个模型纯属给自己找事。

4.3 一套能直接参考的训练参数

这是我在机械+装载模型上最终跑通的参数:

imgsz: 960 batch: 16 epochs: 200 optimizer: AdamW lr0: 0.002 lrf: 0.2 weight_decay: 0.0005 mosaic: 0.8 mixup: 0.1 copy_paste: 0.3 class_weights: loader: 1.0 bucket_raising: 1.5 bucket_dumping: 1.5 excavator: 1.0 bulldozer: 1.2 dump_truck: 1.0 crane: 1.2

训练过程中有两个监控点需要特别关注。第一个,前100个epoch如果某个稀有类别的AP始终在0.3以下,不要急着调模型,先检查这个类别的标签有没有系统性错误,大概率是标注的问题。第二个,mosaic比例不要全程开满。我前50个epoch用0.8,后50个epoch降到0.3,让模型从“见过大场面拼接图”过渡到“标准真实分布”,最终AP比全程0.8高了2个点左右。

扬尘+磁铁这套权重,我用的是YOLOv8s加640输入,数据和增广策略完全独立。扬尘类别开启背景差分门控后的干净样本,磁铁类别做稀有类过采样,mosaic降到0.5。两套模型可以部署在同一张GPU上,进程隔离跑不同摄像头的推理任务。

4.4 评估指标不能只盯mAP

mAP是论文指标,业务侧要的是“每类recall能不能到目标线、误报率能不能压住”。同一套模型在四个场景里,评估维度完全不同:

  • 机械禁区告警,核心是recall。漏掉一台进入禁区的挖掘机,是要出安全事故的。
  • 扬尘喷淋联动,核心是precision。误报一次就会无故喷淋,浪费水还是小事,关键是会造成场面混乱。
  • 装载计数,核心是时序精度,不是单帧精度。帧级漏检可以通过跟踪补回来,但状态机跳变如果频繁,计数就失真。
  • 磁铁状态,核心是magnet_full的recall和magnet_discharging到idle的转换准确率。

上线标准我定的是:连续7天24小时跑真实视频流,按业务指标统计,全部达标才算验收。论文mAP只是过门槛用的,真正决定项目成败的是这套“业务指标矩阵”。

5. 部署与联动:检测框只是第一步

5.1 边缘盒子选型与流处理管线

现场不可能把几十路视频全推到机房GPU服务器做推理,带宽和延迟都撑不住。我用的方案是在边缘侧部署NVIDIA Jetson盒子,就近处理摄像头流,只把事件和抓图传回平台。

管线是这样的:ffmpeg以硬件解码方式拉RTSP流,解码后直接进CUDA显存,交给TensorRT的FP16引擎推理,输出经过ByteTrack做多目标跟踪,再进入业务规则引擎做ROI判断和事件判定。实测在Jetson AGX Orin上,1080p视频流完成“解码+推理+后处理”大概120到250毫秒,满足安全告警500毫秒内的要求。

显存占用也需要提前规划。960输入的一路推理大约占1.2GB显存,640输入占0.6GB左右。一台盒子计划处理几路、跑哪个输入分辨率,一定要先算好显存再去买设备,不然上了现场才发现带不动,非常被动。

5.2 扬尘识别触发喷淋的防抖与回差逻辑

检测到灰尘只是第一步,怎么让它稳定地触发喷淋而不被现场噪声干扰,是更考验工程能力的地方。我的触发逻辑是这样:

  • 检测到dust或heavy_dust,且置信度≥0.5
  • 目标框面积占整幅画面的比例≥8%
  • 连续3帧都满足上面两个条件,才确认一次扬尘事件

事件确认后进入防抖窗口,3秒内重复的扬尘事件只上报一次。这里有一个业务细节很关键——喷淋系统启动后,画面里全是水雾,模型大概率还会觉得“有尘”。如果不做回差,就会出现喷雾→误判扬尘→再喷雾的死循环。

回差逻辑是:面积占比从≥8%降到≤3%,才复位整个判定状态。也就是要等水雾基本散去,系统才允许再次触发。这个数字不是拍脑袋定的,是从真实喷淋视频里统计出来的,水雾残留时间大约在2.5秒左右,所以回差阈值设到3%留了余量。

联动输出用的是Modbus TCP写PLC寄存器,同时在MQTT总线上发布结构化事件。PLC那边收到信号后控制雾炮机组启动。事件数据落库到TSDB,方便后续做扬尘频次趋势分析。

5.3 机械区域闯入告警:多边形ROI加中心点规则

重型机械识别本身只是前提,真正的业务功能是禁区告警。我没有做全画面的机械告警,而是在画面里标定了一个多边形禁入区域。目标中心点落入多边形内、置信度≥0.6、同一个track_id连续5帧都在区域内,这三个条件全部满足才触发告警。

告警证据链必须是完整的,不然安全部门不会买账。每次告警抓取一张现场图片加5秒录像片段,上传到安全平台,并附带目标ID轨迹。这样事后复盘时有据可查,不会出现“系统报了,但没人信”的尴尬。

我在这个环节还踩过一个NMS的坑。扬尘框和挖掘机框大面积重叠时,NMS会把机械框吃掉,直接导致机械漏报。解决方案是在后处理里把机械相关类别在NMS阶段的得分乘以1.1,确保机械框在重叠区域存活。这个小改动,让机械漏报率下降了大概一个量级。

5.4 装载计数与磁铁状态:事件统计才是业务要的“果”

装载计数不能只靠单帧状态检测,因为铲斗举升、翻转这些动作在单帧上总有抖动。我用的是“目标跟踪加状态机校验”:ByteTrack给每台铲车分配ID,状态机定义成“低位→举升→卸料→低位”的闭环,只有完整走完闭环才计数一次。任何一步跳变,比如从低位直接跳到卸料,都判定为无效事件,不计数。

磁铁状态这边的联动逻辑更直接:

  • magnet_full状态持续60秒以上,发出“除铁器已饱和”提醒,让操作员安排卸料。
  • magnet_discharging触发后,如果在30秒内没有回到idle,说明可能卡料或卸料机构故障,需要人工检查。

这两条规则上线后,工艺部门反馈最直接的收获是“终于不用每两小时派人去看一次吸面了”。磁铁状态变化通过TSDB存下来以后,还能画出班次尺度的除铁量趋势曲线,用来判断来料铁件含量是否异常。这套体系里,识别只是起点,事件统计和联动动作才是整个系统真正产生价值的部分。

6. 实测数据与两次典型的误报和漏报攻坚

6.1 上线两周后的整体指标

系统稳定运行两周后,我拉了一版真实场景的离线评估数据:

场景评估样本量Recall@0.5Precision@0.5推理延迟
料场扬尘1000张关键帧0.860.8295ms @640
装卸点装载6000帧连续视频0.930.91110ms @960
基坑重型机械2000张含各距离0.940.92110ms @960
磁铁状态8000张产线抓拍0.970.93110ms @960

数字看起来还可以,但要知道这是我在大量误报修正之后的版本。前两周踩的坑,比模型本身的多得多,这里挑两个有代表性的复盘。

6.2 雾炮喷淋水雾触发扬尘误报的完整排查链路

第一周上线,系统报了一个非常诡异的问题:每天下午3点到5点,喷雾系统每10分钟自动启动一次,但启动之后扬尘告警也立刻触发,然后系统又去启动下一轮喷雾,形成无意义的交替启停。

排查第一步,我把告警记录和雾炮PLC的启动日志做了时间比对。结论是高度吻合,99%的扬尘告警刚好出现在雾炮启动后5秒内。

第二步,人工查看告警抓拍图片,发现画面里全是水雾扬起后的白茫茫一片,人眼都分不清是水雾还是尘团,更别说模型了。

第三步,我做了背景差分回放。统计连续帧里像素变化的比例,发现水雾场景的背景变化率高达0.5以上,因为水雾快速扩散、飘散,画面内容急剧变化。而真实扬尘场景里,尘团是整体漂移的,背景变化率通常在0.2左右,变化速度比水雾慢得多。

于是我在扬尘事件判定的最后一级加了一个门控条件:背景差分变化率超过0.4时,不触发扬尘告警,直接判为“镜头扰动或水雾干扰”。上线后观察两周,误报量下降了96%,同时没有新增漏报。这个案例的核心价值在于:在工业视觉里,很多看似模型层面的问题,其实要用物理过程的差异化特征去解决,图像内容本身的信息量是不够的。

6.3 铲车装载漏计三成的根因修复

第二周,工艺反馈说装载计数的统计比人工记录少了30%。刚开始我怀疑是状态机逻辑有bug,翻了一遍代码没有发现明显问题。然后我把夜班时段的检测输出拉出来单独看recall,发现bucket_dumping在夜间帧的recall只有0.78,远低于白天的0.91。

再往下查,问题出在夜间红外补光上。铲斗斗臂在红外光下反光非常严重,斗臂轮廓和挖掘机的动臂特征高度相似,模型频繁把铲斗姿态框误判成excavator。再加上夜视画面本身对比度低,小框的特征更不清晰。

修复方案分两步。第一步,从现场单独抽了800帧夜间红外视频,重新标注后加进训练集,强化模型对红外光照下铲斗姿态的特征学习。第二步,推理侧对loader姿态类别的置信度做了5帧滑动窗口平滑,单帧的误判不再直接导致状态机跳变。修复后,装载计数与实际人工统计的误差降到了6%左右,已经可以用于日常生产报表。

这类问题的普遍性在于,白天训练集做得再全,也覆盖不了夜间的光照分布变化。工业项目的样本体系,一定要按“时段、天气、季节、光照模式”做分层覆盖,而不是傻傻按场景堆数量。

7. 最后给同行踩坑后的三点建议

7.1 先定义“什么算一次事件”,再去定义“什么算一个目标”

在启动标注和训练之前,先跟环保、工艺、安全三个部门开会,把“一次扬尘告警”“一次装载动作”“一次禁区闯入”“一次除铁器饱和”各自的确切定义对齐。我在这个项目里吃过亏,一开始直接把模型精度做上去了,但业务口径对不上,返工了整整一周。这个顺序千万别搞反。

7.2 先建badcase库,再谈模型迭代

每次模型迭代前,把上一轮上线后的所有误报和漏报案例过一遍,按来源分类,比如天气类、镜头类、目标姿态类、类间混淆类。badcase复盘的时间至少占整个迭代周期的一半。很多“模型精度问题”最后解决起来靠的是数据处理和逻辑规则,而不是换模型结构。

7.3 算力分配要按“业务风险等级”来,不能平均用力

安全相关场景(机械禁入、装载状态异常)给高分辨率、高帧率、低延迟的算力配置;环保相关场景(扬尘)允许低帧率、大延迟,但要做好防误报逻辑;工艺相关场景(磁铁状态)用轻量模型加事件统计。四类任务放到一个盒子上跑,只有做好算力分级,才能让所有业务同时满足各自的SLA。

最后再分享一个小技巧:给所有检测框的事件数据统一加上“摄像头ID+画面时间戳+模型版本号”这三个字段。出问题的时候,按这三个字段能快速定位到具体某一路摄像头的某一段时间的某一次模型判断,排查效率能提升好几倍。这比什么优化技巧都实用。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询