ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

传送带异物检测数据集构建:从YOLO标注到训练闭环的完整指南

传送带异物检测数据集构建:从YOLO标注到训练闭环的完整指南 刚接传送带异物检测项目那阵子我在测试集上把模型的mAP50调到了0.95当时觉得稳了结果一上现场就翻车。不是漏检螺丝刀就是把皮带接头当成异物狂报警现场运维三天两头打电话投诉。后来复盘才发现问题根本不在模型结构而是在数据集构建阶段就埋了雷。标题里的三个关键词——YOLO、多格式标注、数据集构建听起来都不难但凑到工业传送带这个场景里每一步都有公开教程没讲透的坑。这篇东西我打算把完整的构建链路捋一遍从采集、标注、格式管理到训练闭环尽量写得能直接照着执行。1. 传送带异物检测为什么容易“实验室可用、现场废掉”做工业视觉的人应该都有体会产线项目最大的成本不是GPU和模型调参而是数据。对外行人来说传送带异物检测无非就是“拍几张照片框出异物训练一个YOLO”。但真正做过的人清楚这件事最难的地方在于异物这个类别的内部差异比不同类别之间的差异还要大。一块矸石、一段钢丝绳、一个矿泉水瓶、一团编织袋碎片它们在图像上长得完全不一样可都属于“异物”。1.1 场景定义比算法选型更重要开始做数据集之前我建议先花一整天跟现场工艺、设备、运维的人聊明白一个问题你们说的异物到底指什么是有形的固体废料比如煤流中的锚杆、托盘、木块还是包括物料本身的超粒度比如大块原矿不同的定义直接决定你的标注类别体系、检测目标和数据采集策略。我遇到过一个比较典型的需求用户要检测的是“一切不属于正常物料的东西”。这个定义听起来很全但落到标注标注时就麻烦了——皮带在运煤和运矿石时正常的物料长相差很多同一个语义“正常”在不同工况下的视觉特征是变化的。如果数据集里只拍了晴天白料模型一遇到黑料或者水煤就崩。所以我的建议是把检测目标收敛成几个可定义的类别比如金属异物anchor、托盘、钢丝绳、纤维异物编织袋、棉纱、块状异物矸石、木块再加一个“other”兜底。每个类别都要有明确判定规则而不是笼统的“异物”。1.2 传送带场景给数据带来的四个特殊约束传送带检测跟一般的图片分类、目标检测数据集构建相比有几个不太容易注意到的特殊性目标尺度极端不平衡远处的小螺栓可能只有十几像素近处的大矸石能占画面的三分之一。YOLO系列对小目标的召回本来就相对弱如果数据集里小目标占比不够训练出来的模型基本对小异物视而不见。运动模糊普遍存在皮带速度通常在0.5~2.5m/s快门不够快的话任何运动目标都会有拖影。拖影样本可以少量保留作为困难样本但绝不能占主流。光照和背景极不稳定白班和夜班、晴天和雨天、物料颜色深浅都会让图像分布漂移。构建数据集时如果只收集某一时段的数据模型的泛化能力一定差。正常样本和异常样本比例悬殊多数时间传送带上是干净的异物是小概率事件。按时间抽样采集的话正样本会严重不足而且很容易漏掉那些真正值得学习的困难样本。这四个约束最终都指向一个结论数据的质量天花板在采集阶段就已经定了标注和后处理只能逼近这个天花板无法突破。2. 现场采集方案数据集的“上限”在这里就决定了很多团队做数据集是从网上找公开图片或者去现场随便拍个几百张就开始标。这在工业场景里基本行不通因为公开数据集里的目标形态、视角、背景和你的现场完全是两码事。我们当时走通的是下面这套流程。2.1 相机、镜头与光源的选型心法传送带检测一般用可见光工业相机。分辨率建议不低于500万像素具体看你要覆盖多宽的皮带。如果一根皮带宽度1.2米你希望25mm的螺栓能被可靠识别那视场里每个像素对应的物理尺寸最好不超过2mm这样算下来至少需要600万像素。不要迷信高分辨率像素高了数据量、标注量、训练耗时都上去了关键是够用。镜头方面我建议用定焦工业镜头12mm或16mm比较常见不要用自动变焦的安防镜头因为现场震动和电机会让自动对焦“抽搐”。光源推荐条形光源或同轴光源斜射能增强表面纹理让异物更突出。安装位置尽量选在皮带平稳段、没有托辊遮挡的地方高度要能覆盖整个带宽。真正决定图像能不能用的关键参数是快门速度。传送带线速度假设是1.5m/s目标在画面中移动如果快门只有1/250s那运动位移大概有6mm在2mm/pixel的分辨率下就是3个像素的拖尾小目标的轮廓直接糊掉。我们当时直接拉到1/1000s到1/2000s再配合补光这样单帧运动位移控制在1像素以内图像就足够锐利。2.2 视频抽帧比连拍更高效刚开始我们是用相机连拍模式在现场蹲守结果一天下来拍了上万张里面大量是重复的、空荡荡的背景图清理工作量大到让人崩溃。后来改成录视频再离线抽帧效率高了一个量级。流程是用工业相机或高帧率相机录制一段时间内的皮带运行视频建议不少于连续4小时覆盖不同时间段然后把视频按固定间隔抽帧或者按“画面有变化”做动态抽帧。视频抽帧的好处是你可以事后回看能精准找到异物出现的那几秒钟不会漏掉目标。抽帧帧率不需要高2到5fps就足够了因为皮带上的目标从进入视场到离开视场大约有1~2秒抽5帧能保证每个目标有5到10个样本。有个细节值得注意抽出来的帧如果间隔太近同一目标在连续帧上会高度相似直接全部丢进训练集容易造成“时间邻近重复样本”问题让模型在验证集上表现虚高。我的做法是同一目标的多帧只保留2~3帧并且训练集和验证集错开不同的时间段。2.3 负样本不是垃圾是防误报的防线很多初学者做异物检测数据集只关注异物——正样本。但传送带上的背景本身就有很多“看起来像异物”的东西皮带接头、托辊阴影、水渍反光、物料飞溅、货架边缘。这些东西在推理时都会是干扰项。所以我会专门从视频里截取很大一批“无目标帧”不标任何框作为纯背景负样本。这批负样本看似空洞却能让模型学会“看见这些场景时不要输出任何框”。在工业部署里误报比漏报更致命——误报多了控制室把系统的报警阈值调高等于废了这个模型。负样本在训练集中的比例我一般控制在15%到30%太少压不住误报太多会稀释正样本的学习效率。3. 标注规范类别边界定清楚了团队才不会打架标注是数据集构建里人力投入最大的一环也是最容易出乱子的一环。传送带异物检测有个天然难题同一张图两个人很可能框出完全不同的结果。有人按目标的外接矩形框有人只框出目标的“实体部分”有人把连接在一起的多个金属碎片标成一个框有人标成多个框。3.1 与工艺人员一起敲定类别体系类别体系不是算法团队自己拍脑袋定的事。我建议把标注类别草案拿到项目评审会上和现场工艺人员一起过一遍。你在标注界面里写的每个类别都要有对应的现场实物图。比如“金属异物”下面还可以拆成“钢板类”“线材类”“紧固件类”但类别太多会加大标注负担和类别不平衡类别太少又会让模型内部的语义空间过于混杂。以我当时做的铁矿传送带项目为例最终确定的类别是四个类别典型物判定要点anchor锚杆、锚索、托盘带螺纹或异形金属件长条状为主wire钢丝绳断头、铁丝、电缆细长柔性金属可弯曲fabric编织袋、棉纱、塑料薄膜柔性非金属表面有纹理block矸石、大块原矿、木块大尺寸硬质物通常超过正常粒径这套体系有一个共同的好处每个类别在形状、纹理、材质上有一定的区分度模型不容易混淆。真正难分的是block和正常大块矿石之间的边界这个只能靠标注规则里写清楚“粒度超过阈值才算异物”来解决。3.2 边界框标注的三条硬性规则边界框怎么标直接决定了YOLO训练时标签的稳定性。我们最后固化了三条规则标注员必须遵守只框目标的可见主体轮廓如果目标被遮挡超过50%这一帧不标遮挡小于50%按可见部分的最小外接矩形框来标不允许把遮挡物一起框进去。运动模糊严重的不标但单独抽出来存成难样本库模糊标注框会让模型在训练时学到错误的边缘信号得不偿失。同一物理目标在连续帧中保持相同类别不要因为目标旋转、变形就改标签这是标注一致性的大忌。这三条规则看起来简单真正执行起来需要标注组长抽查。我建议每周抽10%的已标注数据做二次复检重点看类别是否稳定、是否存在漏标框。3.3 多人标注时的一致性验证如果你有多个标注员不要只看每个人标了多少张还要看他们之间是否真的统一了标准。一个简单可用的指标是Kappa系数。实际操作中可以让两个标注员对同一个大约100张的小样本集分别标一遍然后把每个目标类别和位置的判定结果放到混淆矩阵里计算Kappa。Kappa大于0.7基本合格低于0.5说明标准还需要再对齐。这个环节会被很多小团队忽略等训练完看confusion matrix发现metal和fabric互混得厉害回头排查才发现是标注员A把所有发亮的东西都叫metal标注员B只把金属光泽明显的东西叫metal。这种事在项目初期花一天对齐能省后期几个星期的返工。4. 多格式标注管理的正确姿势一条主格式按需导出“多格式标注”这个需求我理解大多数人是这么踩坑的先用LabelImg存了一批VOC格式XML后来因为要转YOLO写脚本把XML转成TXT再后来要跑COCO评测又写了XML转COCO JSON的脚本中间发现label名字写错又回去改了原始XML但已经导出的TXT和JSON不会自动同步更新。项目进行到一半三种格式各自为政已经分不清哪个是权威数据了。4.1 把COCO JSON固定成唯一主格式经过几次折腾我现在的方法是无论用什么工具标注最终都汇总成一份COCO格式JSON作为全项目的唯一真源。YOLO训练用的TXT、Roboflow增强用的格式、评估脚本需要的COCO输出全部从这一份JSON按需脚本化导出。为什么选COCO而不是YOLO TXT做主格式因为COCO JSON自带图片尺寸、类别ID、目标区域等信息语义更丰富也更容易做后续的数据增广和拆分。YOLO TXT只是一个极度压缩的产物缺少图片级元信息反向转换时容易丢数据。另外COCO JSON本身是标注工具和很多开源库的直接输入输出格式兼容性更好。需要明确的是我并不是让你在项目里同时维护多份标注。标注员在标注工具里打标导出COCO JSON训练前跑一个转换脚本生成YOLO数据集。任何标签的修改都在标注工具里完成然后重新导出JSON再重新生成TXT。核心是主格式唯一派生格式随用随生成。4.2 标注工具选型LabelImg还是CVAT这两款工具我都用过分别适合不同的阶段。工具优势劣势适用场景LabelImg零安装成本、单机离线可用、对YOLO/VOC格式友好多人协作能力弱、无自动标注插件个人项目或小组标定样本量千级CVAT支持在线多人协作、内置AI辅助预标注、导出格式丰富需要部署服务需要维护权限和任务团队标注管线样本量万级以上我的建议是如果只是个人开发或毕设用LabelImg就够了Excel表格里记一下哪些图分给了谁即可。如果是现场项目且标注量大直接上CVAT。CVAT里的AI辅助标注可以先用一个初始YOLO模型做预标注标注员只需要调框速度能提升不少。我把这个流程跑顺之后一个熟练标注员一天可以处理800~1200张图而纯手动标注极限大概在400张左右。无论用哪个工具都让标注员直接输出COCO格式不要让他们手动维护任何TXT文本标签。人在传入TXT文件时出错率远高于图形界面的交互。4.3 一次跑通的COCO转YOLO脚本下面这个脚本是我在项目里一直沿用的简化版作用是把COCO JSON转换成YOLO格式的TXT文件并按train/val划分子集。核心逻辑有两点一是把框坐标从COCO的[x, y, w, h]转成YOLO的归一化[cx, cy, w, h]二是过滤掉宽度或高度小于一定阈值的目标因为过小的框在YOLO训练中往往属于标注噪声。import json import os from collections import defaultdict def coco_to_yolo(coco_json_path, output_dir, min_size2): with open(coco_json_path, r, encodingutf-8) as f: coco json.load(f) img_id_to_info {} for img in coco[images]: img_id_to_info[img[id]] { file_name: img[file_name], width: img[width], height: img[height] } cat_id_to_index {} for idx, cat in enumerate(coco[categories]): cat_id_to_index[cat[id]] idx anns_by_img defaultdict(list) for ann in coco[annotations]: x, y, w, h ann[bbox] if w min_size or h min_size: continue anns_by_img[ann[image_id]].append(ann) for img_id, anns in anns_by_img.items(): img_info img_id_to_info[img_id] base_name os.path.splitext(img_info[file_name])[0] out_path os.path.join(output_dir, base_name .txt) with open(out_path, w, encodingutf-8) as f: for ann in anns: x, y, w, h ann[bbox] cx (x w / 2) / img_info[width] cy (y h / 2) / img_info[height] w_n w / img_info[width] h_n h / img_info[height] cat_idx cat_id_to_index[ann[category_id]] f.write(f{cat_idx} {cx:.6f} {cy:.6f} {w_n:.6f} {h_n:.6f}\n)注意YOLO的类别索引从0开始所以你在写datasets.yaml时names列表的顺序必须和这里cat_id_to_index的映射保持一致。很多人的坑就出在这里写COCO JSON时类别ID可能从1开始转换时忘了从0开始训练时类别错位模型自然全乱。4.4 目录结构按YOLO标准来组织转换完之后目录结构我习惯固定成下面这样可以直接配合Ultralytics YOLOv8使用dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ └── data.yamlimages和labels里的文件名必须一一对应后缀不同而已。同一个图片的标注TXT放在labels的同一级子目录下图片放在images的子目录下。这个目录结构是YOLO训练器的默认约定也方便其他框架直接读取。另外验证集里一定要保留一批纯背景负样本图这些图对应的TXT是空的不要删除。5. 数据划分与质量自检训练前最后一道闸门在做数据集划分时最常见的错误是随机划分。你会发现验证集的分布和训练集几乎一样模型在验证集上分数极高一上现场又拉胯。因为工业数据有时间连续性同一小时的相邻帧长得太像随机划分会让“时间泄漏”发生。5.1 按时间段划分而不是随机划分正确的做法是按采集时间做划分。比如前两周采集的数据做训练集第三周数据做验证集第四周之后的数据做测试集。这样模型的验证指标才真正反映它在“没见过的时间段”上的表现。具体到传送带场景我还会看目标类别的分布。异物是小概率事件如果整个数据集里只有一个礼拜在矸石特别多的情况下采集那么这类目标大量集中在那个时间段里。按时间划分后验证集里可能完全没有矸石样本。这时候就需要对特定稀少类别做跨时间段补充采集而不是强行从训练集里挪几个样本到验证集里包住类别——那样又回到了随机划分的思维陷阱。按时间切分的比例一般是6:2:2但前提是各个时间段里类别分布不要偏差太大。如果某个类别在验证集里没有样本宁可增加该类别的数据也不要靠随机划分来掩盖数据覆盖不足的问题。5.2 标签质量自检不要相信任何人的手不管标注员多认真最终训练前都要跑一遍自动检查。下面是我固定会做的几个检查项坐标范围检查所有归一化坐标必须在0到1之间任何越界值都说明转换脚本或标注工具有问题。框尺寸分布检查统计所有标注框的面积分布如果出现大量的1~2像素宽高的框这些大概率是标注噪声如果整个数据集的框面积都集中在很小范围说明采样策略对小目标不友好。类别数量统计打印每个类别的实例数和图片数如果类别间数量差超过5倍就要考虑人工补样本或者用数据增强来平衡。空标签图检查确认哪些图没有目标这些空标签文件是否被正确放在了labels目录里。这些检查我一般写成一段简单的Python脚本每次数据集更新后跑一遍。所谓“质量自检”不是考前突击而是标准流水线的一部分。5.3 硬负样本库误报问题的解药前面提到纯背景负样本这里再展开说。我单独建了一个“硬负样本库”专门存放那些“让模型容易出错”的图片皮带接头区、托辊反光、水迹、影子、物料纹理交替区域等。每次训练完一版模型把验证集里误报率最高的图挑出来合并进硬负样本库下一轮训练时再混合进去。这个库是持续增长的从最初的几十张逐渐积累到项目末期可能有一两千张。模型对误报的抵抗能力很大程度上靠这个库撑着。很多团队数据指标提不上去就是因为他们只在正样本上死磕忽略了“模型别乱说话”这件事同样需要数据来教。6. 和YOLO训练闭环联动数据集要能快速迭代严格来说构建数据集的最终目的是服务训练所以这里简单讲一下数据集需要配合YOLO训练端做哪些调整。我用的是YOLOv8它比之前的版本省心不少但该踩的坑一个不少。6.1 写一个不会出错的datasets.yamlYOLOv8的dataset配置是一个YAML文件关键点是path要写绝对路径train和val写相对于path的路径。很多人训练时报错No labels found十有八九是路径没配对。path: /data/projects/belt_dataset train: images/train val: images/val test: images/test nc: 4 names: [anchor, wire, fabric, block]names的顺序就是TXT里类别索引的顺序如果你在转换脚本里用的索引是0~3这里就必须对应。任何一次新增类别或调整顺序都要重新生成一次TXT并验证一遍标签索引这类问题最隐蔽。6.2 训练阶段三个常见问题与对策训练过程中我常遇到三个问题其实根子都在数据集train loss下降val loss不降反升大概率是训练集和验证集分布不一致也就是划分泄漏。回头检查一下是不是同一个目标的连续帧被同时切到了两边或者某个场景时段被全量放进了训练集。小目标类别AP很低YOLOv8本身对重叠和遮挡鲁棒性不错但数据里小目标占比过低采样时无法得到充分学习。我当时的做法是把包含小目标的图片复制一份并做增强随机裁剪放大、mosaic提高小目标在batch中的出现频率而不是简单把所有图片分辨率拉高。置信度阈值在0.5时误报一堆调到0.8又漏检这是数据分布没覆盖住等价易混样本的表现。正确解法不是调阈值而是把误报样本收集进硬负样本库把漏检样本作为困难正样本回填进训练集下一轮迭代再训。6.3 评估指标不要只盯mAP50工业现场最关心的通常是“每班次误报次数”和“漏检率”。mAP50只是开发阶段的一个参考不能代表上线后的体验。我在迭代过程中会额外关注验证集的confusion matrix和F1-Confidence曲线用它们来帮助判断哪个类别的混淆最严重、当前最优置信度阈值该取多少。另外一个值得养成的习惯就是按周迭代。每周从现场抽回新数据标注合并入数据集重新训练并上线对比。数据集工程不是一次性的动作而是一台持续运转的机器。刚开始迭代时可能一周只能加几百张图坚持一阵子之后数据集自然会长成和现场吻合度很高的形态。最后分享两个小经验。第一项目最初期哪怕只有两三百张图也建议把整套采集-标注-训练-评估管线都跑通一遍哪怕模型效果很差。管线通了后面所有优化都是线性叠加管线不通数据集扩到两万张也只是给自己增加返工量。第二标注规范一定要打印出来贴在实际工作墙上而不是放在云文档里吃灰。标注员每天抬头看见“遮挡超过50%不标”“模糊不标”这两条比什么验收标准都管用。构建一套可靠的传送带异物检测数据集本质是在回答三个问题现场长什么样、什么才算异物、模型又要避开哪些误会。把这三个问题用数据回答清楚YOLO的训练反而变成了顺理成章的事。
返回列表