简介:面向AGV仓储机器人识别任务的目标检测数据集,适合深度学习与计算机视觉学习者、机器人方向研究者使用。数据集共标注3个类别,包含G1PB2000_Paleteira_AGVS BYD、G1RB5000、AGV-P等典型仓储设备,图片数量1514张,覆盖多角度作业场景。压缩包共2000个文件,内含1510个txt标签、489个xml标签及1个yaml类别配置文件,txt格式可直接用于YOLO系列算法,xml格式适用于Faster RCNN、SSD等模型训练。图片与txt标签已按训练集、验证集、测试集划分完毕,无需额外整理,可直接投入YOLOv5至YOLOv10各版本训练流程。资源包总大小82.36MB,目录结构简洁,方便检索与替换。目前已有383人学习下载,对于需要快速获取仓储AGV检测数据的开发者而言,可省去标注和格式转换环节,专注模型调参与应用落地。
1. AGV仓储机器人识别数据集:先把“仓库视角”喂给目标检测模型
不少AGV项目在联调阶段栽在一个共同点上:模型在演示视频里检测得又准又稳,一放进真实仓库,货架反光、昏暗巷道、多车交汇就把检测框打得七零八落。这时候才意识到,AGV调度系统的路径规划再聪明,视觉感知吃进去的如果是不对味的数据,输出也是一堆晃动框。AGV仓储机器人识别数据集就是为这个场景准备的训练数据,覆盖AGV本体、货架、托盘、行人、料箱等仓储目标,用于训练目标检测模型,让车辆在巷道、出入库口、充电区都能稳定输出检测框。这篇内容按我实际做过的方案往下写:标签体系怎么定、数据怎么收、VOC/COCO怎么转成YOLO格式、训练参数怎么设、常见坑怎么排。
2. AGV仓储场景的标签体系设计:哪些目标“不能标错”
2.1 五类基础标签:框什么、不框什么
做AGV仓储识别数据集,第一步不是打开标注工具,而是先把标签体系写成一页纸。我一般固定成五类:agv、shelf、pallet、person、box。这五类基本覆盖了一个仓储机器人视觉感知的绝大部分需求。
| 类别 | 框选范围 | 漏检后果 | 标注难点 |
|---|---|---|---|
| agv | 整车轮廓,含底盘和顶升机构,不含所载货架/托盘 | 交汇碰撞 | 多车同框时相互遮挡 |
| shelf | 货架框体,不标托盘和货箱 | 取放货失败 | 远距离下框太小,且有斜撑 |
| pallet | 托盘外边界 | 叉取失败 | 纹理弱,和地面颜色接近 |
| person | 人体最小外接框,含叉车司机 | 人身安全风险 | 遮挡、反光背心过曝 |
| box | 料箱、临时堆物 | 避障误判 | 外观差异极大,纸箱/塑料箱混放 |
这里最关键的是agv和shelf的边界。AGV空载时本身就带一个驮架,如果标注时把驮架也算成shelf,模型在空载AGV经过货架时会同时输出两个高度重叠的框,调度系统拿到这种结果很难做决策。所以我给标注组的规则是:货架类只标固定货架,AGV上的驮架永远算进agv框里,不单独拆出来。
2.2 数据来源与组合比例:现场拍摄为主,公开与合成做补充
数据集的主体必须来自真实仓库,这是所有后续工作的地基。常见做法是三路组合:真实现场采集占六到七成,公开数据补通用类占两成,合成数据补长尾占一成。公开数据集能补的是person、pallet这类通用目标,agv和shelf几乎没有现成可用的公开数据,只能靠现场拍。
现场采集时不要对着视频流逐帧截。AGV的相机一般25fps,连续截取会造成上下两帧高度重复,等于把同一样本复制了好几遍。建议每5-10帧抽一帧,并且让AGV在巷道里来回跑,覆盖不同光照、不同角度、不同负载状态。镜头位置也要分开:顶装广角、叉臂侧视、固定工位斜视,三种视角分别建目录,不要混在一个文件夹里,后续切分数据集时才知道视角分布是否合理。
2.3 标注规则的四个约定:遮挡、截断、反光、类别稳定性
标注规则里最容易出问题的是遮挡和截断。我在项目里定的标准是:遮挡超过60%的目标不标,截断超过50%的目标不标,遮挡轻微的必须标。这样做的原因是,训练时同一个目标一会儿有框一会儿没框,模型学到的特征就是混乱的;与其勉勉强强给半个框,不如让模型先把完整的、清晰的形状吃透。
反光背心是仓储场景的特色难点。工人在强光下穿的荧光背心经常过曝成一片亮斑,外形轮廓完全丢失。这种样本不能删,反而要专门多收集,否则模型在白天窗口光照强烈的时段会频繁漏人。还有一条硬性规则:同一个物理目标在连续帧里不能一会儿叫agv一会儿叫shelf。标注员中途改判断标准的事情太常见了,必须在标注规范里写明“以首帧判断为准”,否则转换格式之后数据里全是矛盾样本。
2.4 数据组织:按session划分,别让验证集泄漏
数据集切分时,如果按单帧随机划分,同一个巷道里第一帧分到train、第二帧分到val,两张图几乎是一模一样的,训练还没开始验证集的mAP就已经虚高了。我一般按session划分:AGV完成一次完整行走任务的所有帧算一个session,train和val按session粒度切分,保证同一个巷道场景不会跨集合出现。目录结构上建议加session_id层级,用CSV维护每帧的采集状态,转换脚本直接读CSV而不是扫文件夹,这样多人协作时也不会互相覆盖。
3. VOC/COCO转YOLO:数据集落地的脚本与四个边界坑
3.1 YOLO标准目录结构与data.yaml
标注工具导出格式常见有两种:LabelImg导出VOC xml,x-anylabeling可以导出COCO或YOLO格式。不管源头是什么,最终都要整理成YOLO系列的目录结构:
agv_dataset/ images/ train/ val/ labels/ train/ val/ data.yaml图片和txt标签一一对应,txt每一行是“类别ID x_center y_center width height”,坐标都是归一化到0-1的浮点数。这个结构对YOLOv5、YOLOv8、YOLOv11都通用,后续换模型不需要重新转换数据。
3.2 从VOC xml转YOLO txt:最小可用的Python脚本
如果源头是LabelImg的VOC格式,下面这个脚本是转换的核心:
import os import glob import xml.etree.ElementTree as ET # 类别顺序是数据集全局唯一的ID,一旦确定不要轻易改 CLASSES = ['agv', 'shelf', 'pallet', 'person', 'box'] def voc_to_yolo(xml_path, out_txt_path): tree = ET.parse(xml_path) root = tree.getroot() # VOC的size节点存的是原始图像尺寸,但有些工具会写缩略图尺寸 img_w = int(root.find('size/width').text) img_h = int(root.find('size/height').text) lines = [] for obj in root.findall('object'): name = obj.find('name').text if name not in CLASSES: continue cls_id = CLASSES.index(name) box = obj.find('bndbox') x1 = float(box.find('xmin').text) y1 = float(box.find('ymin').text) x2 = float(box.find('xmax').text) y2 = float(box.find('ymax').text) # 过滤顶点顺序错误的框,避免后续训练直接nan if x2 <= x1 or y2 <= y1: continue x_center = ((x1 + x2) / 2) / img_w y_center = ((y1 + y2) / 2) / img_h w = (x2 - x1) / img_w h = (y2 - y1) / img_h lines.append(f'{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}') with open(out_txt_path, 'w') as f: f.write('\n'.join(lines))这个脚本逻辑不难,但要点都在细节里。CLASSES列表的顺序就是后面data.yaml里names的顺序,这个顺序一旦定下来就不能再改,否则训练时类别ID对不上,训练不报错但指标会变成一锅粥。
img_w和img_h直接读xml的size节点,坑在于有些标注工具导出的尺寸和原始图像不一致。建议转换前用PIL或OpenCV读取实际图片尺寸覆盖xml里的值,以实际图为准。
坐标归一化之后要检查边界。标注时鼠标拖过图像边缘很容易让x2超出图像宽度,归一化后直接变成大于1的数。稳妥的做法是转换后做一次clip到0-1区间,再把越界的文件名打到一个日志里,人工抽查这些样本,而不是直接删掉。
3.3 四个边界坑:越界、小目标、空标签、类别ID移位
第一个坑是坐标越界。现象是归一化后的中心点或宽高大于1,训练时loss曲线正常但验证集AP波动剧烈。原因是标注框拖出图像边缘或者标注工具自身的bug。解决方法是脚本里捕捉x2 <= x1或y2 <= y1的目标,过滤后单独落一个skip.log文件,方便回头定位。
第二个坑是小目标过滤。一张1920x1080的图中,一辆远距离AGV可能只有30x40像素,归一化后宽高约0.016。这类框如果大量存在,模型学不到有效特征,反而干扰。我的习惯是保留,但如果框宽或高小于图像的2%,会考虑在训练时配合切图处理,而不是直接删,因为删了之后模型就再也见不到远距离目标了。
第三个坑是空标签。纯背景图没有目标,不该生成空txt。YOLO训练时txt存在但内容为空会警告甚至影响dataloader,所以纯背景图的标签文件直接不生成。代码里控制即可,不用额外标记。
第四个坑是类别ID移位。比如刚开始标了六类,中间把“agv_tray”这类删掉,后面的txt里所有类别的ID都整体错位,模型却不会报错。解决方法是转换脚本里不直接存数字文件,而是每批转换后用一个统计脚本打印每个类别的样本数,人工核对数值比例是否合理。
3.4 可视化校验:转换完先画框再训练
转换完成不等于数据可用,一定要先做可视化抽查。下面这个脚本从训练集随机抽20张图,把YOLO txt的框画出来:
import cv2 import os import random CLASSES = ['agv', 'shelf', 'pallet', 'person', 'box'] def draw_yolo_boxes(img_path, txt_path, out_path): img = cv2.imread(img_path) h, w = img.shape[:2] if not os.path.exists(txt_path): return with open(txt_path) as f: for line in f: parts = line.strip().split() cls_id = int(parts[0]) xc, yc, bw, bh = map(float, parts[1:]) x1 = int((xc - bw / 2) * w) y1 = int((yc - bh / 2) * h) x2 = int((xc + bw / 2) * w) y2 = int((yc + bh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(img, CLASSES[cls_id], (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2) cv2.imwrite(out_path, img) if __name__ == '__main__': img_dir = 'agv_dataset/images/train' label_dir = 'agv_dataset/labels/train' out_dir = 'check_vis' os.makedirs(out_dir, exist_ok=True) imgs = random.sample(os.listdir(img_dir), 20) for img_name in imgs: stem = os.path.splitext(img_name)[0] txt_path = os.path.join(label_dir, stem + '.txt') draw_yolo_boxes(os.path.join(img_dir, img_name), txt_path, os.path.join(out_dir, stem + '.jpg'))画出框之后,重点看两类问题:一是框有没有整体偏移半个车身,这往往说明标注工具的坐标系设置有问题;二是同一目标在两张连续帧里类别是否一致。肉眼扫一遍20张图通常就够,不需要每张都看。
4. 用YOLOv8训练AGV仓储识别数据集:目录、参数与怎么看结果
4.1 data.yaml配置文件
数据集落好之后,训练的第一步是写data.yaml。YOLOv8的训练入口会自动读取这个文件:
path: /data/agv_dataset train: images/train val: images/val nc: 5 names: ['agv', 'shelf', 'pallet', 'person', 'box']path字段建议用绝对路径。YOLO对相对路径的支持有些隐性问题,换机器跑的时候相对路径很可能解析到模型目录而不是数据集目录。团队协作时统一约定数据集的挂载路径,能省掉一大半“为什么训练时图片加载为0”的报错排查时间。
4.2 训练命令与关键参数
数据量在3000张左右、每类目标不少于2000个instance时,可以直接用YOLOv8训练:
yolo detect train \ data=/data/agv_dataset/data.yaml \ model=yolov8n.pt \ imgsz=1280 \ batch=16 \ epoch=100 \ patience=15 \ workers=8 \ device=0 \ lr0=0.01 \ mosaic=1.0参数选择背后是AGV仓储场景的特点。imgsz我习惯给1280而不是默认的640,因为仓储场景里远距离的托盘和行人占了相当大的比例,分辨率太低时这些目标只有十几个像素,特征根本传不上去。代价是显存占用明显增加,batch=16在2080Ti上接近上限,显存小的机器把batch降到8配合amp混合精度训练。
model参数用yolov8n.pt还是yolov8m.pt要按工控机算力来。AGV车载设备一般是Jetson系列或瑞芯微芯片,算力不高,nano模型更容易跑到实时,所以训练端选nano粒度更贴近部署。如果项目不着急上线、设备算力充足,可以试试medium版本,mAP一般能再涨两三个点。
lr0用0.01适用于从COCO预训练权重开始微调的情况。如果是在自己已有的AGV数据集上继续训练,学习率要降到0.001,否则前面几轮loss就可能震荡。
mosaic数据增强在训练后期建议关掉。AGV场景里货架和托盘经常互相遮挡,mosaic会把四个不同场景的图拼在一起,让模型学到“货架上叠加半个托盘”这种根本不存在的组合。我在实际项目里的习惯是前80轮开mosaic,最后10-20轮用mosaic=0.0收尾,让模型重新看清真实的目标边界。
4.3 训练结果怎么看:哪些指标指向数据集问题
训练跑完,先看runs/detect/train目录下的results.png。这张图里最该关注的是train/val两条loss曲线是否同步下降。如果val loss降到一定程度后开始回升,说明过拟合了,这往往不是模型问题,而是某个类别的样本模式太单一,模型把训练集里的固定角度背了下来。
再看confusion_matrix.png。AGV仓储数据集最常见的混淆是agv被误判成shelf,因为空载AGV本身就长着一副货架的样子。混淆矩阵里这两个类目的交叉值如果超过10%,基本能确定标注时驮架和货架的边界没有分开,回到标注规范去补正,而不是继续调NMS阈值。
最后一招是打开val_batch*.jpg预测图,直接看预测框是否贴合目标边缘。这一步很多工程师跳过了,实际上它是检验数据集质量最直观的方式。框明显偏大或者偏向一侧,八成是某位标注员把框拖宽了一两个像素,这种事看曲线永远看不出来,看图一眼就露馅。
4.4 数据量不够时:先扩数据再调模型
训练集中某个类别instance少于1000时,YOLO的表现会明显偏科。最常见的处理办法是给这个类别做重复采样,把该类的样本复制几份放进训练集,同时控制其他类别不变。这本质上不是给模型增加信息,只是让它在训练时多“看”几遍。真正有效的补充还得靠采集和合成数据,这部分放到第6章展开。
5. AGV仓储识别数据集的踩坑实录:现象、原因与排查流程
5.1 模型把AGV屏幕和反光识别成货架
现象:仓库里的广告屏、铁皮柱反光区域被持续输出shelf框,防撞条边缘也出现大量假阳性。
原因:标注时货架的框拖得太宽松,把货架边缘的阴影、反光一并包了进去,模型学到的是“高对比边缘”这个表面特征,而不是货架结构本身。
解决:把货架标注规范改为框贴结构边缘,留1-2像素余量即可,同时单独收集一批只有反光、没有货架的负样本图放进训练集。负样本不生成标签txt,模型会在这些图上学会抑制误报。
5.2 远距离AGV严重漏检,近距离框却贴得很准
现象:验证集里大尺寸目标的AP在90以上,小尺寸目标AP只有50出头,整个类别的mAP被拉低。
原因:数据采集时AGV都在主巷道近景,远景样本极少,模型几乎没有见过几十像素大小的AGV。
解决:把imgsz从640调到1280甚至1536,让远景目标的像素占比变大;同时从原始大图中做切图,把一张1920x1080图切成左右两半,等同于把远景目标“放大”了一倍。切图后注意把对应的标签坐标也按切图偏移量重新计算。
5.3 验证集mAP虚高,实拍表现对不上
现象:训练集val mAP到96%,拿到真实巷道一跑,漏检一辆AGV或者追丢一个行人,落差非常大。
原因:数据划分时按单帧随机切分,同一个session的帧被分到了train和val两边,验证集里全是训练集的“近亲”,指标自然好看。
解决:按session粒度划分。一个session是AGV一次完整任务的连续帧,切分时保证session整体落在train或val,不允许跨集合。划分后运行一段检查脚本,统计所有图片文件名前缀,确认两边没有重叠的session编号。
5.4 类别严重不平衡,货架被料箱淹没
现象:box类instance占总量60%,shelf类只有5%。训练后模型看到货架就倾向输出box,货架自身的AP一路下滑。
原因:采集时工位附近堆料场景多,素材重复;货架样本采集量又严重不足。
解决:先把每类instance控制在2000-5000区间,超出的类别降采样,不足的类别做重复采样。再从原始素材里找货架角度的补充视频,重新走一遍抽帧、标注、转换流程。类别不平衡靠数据增强救不回来,只能靠数据配比。
5.5 训练loss正常但person框高度飘忽不定
现象:person类召回率尚可,但预测框有时是头肩框、有时是全身框,高度忽大忽小。
原因:标注团队里不同成员对“人的框选范围”理解不一致,有人从头到脚框全身,有人只框头肩和安全帽。
解决:标注规范里给出示例图,明确画出行人最小外接框的上下边界;再用脚本统计所有person框的高度分布,如果出现明显的双峰,说明规范还没统一。这个统计脚本很简单,读所有txt里person框的高度画个直方图,双峰出现就要返工。
排查顺序我建议固定成一套:先看train和val的图片文件名有无session交叉,再看每类instance数量分布,接着可视化抽查20张图,最后才轮到训练后的混淆矩阵。这套顺序能覆盖九成以上的数据集问题,不要一上来就翻模型参数。
6. 补长尾的合成数据与部署前验收:让数据集真正跑在AGV调度系统上
到了进阶阶段,真实样本的边际收益会越来越低。仓库里最缺的不是常规货架样本,而是AGV交汇遮挡、托盘半探出货架、逆光暗角这类长尾帧。合成数据是补长尾的常用做法,我在工程上用的是Blender与Unity两套路线,核心是把3D场景里的标注坐标自动投影回2D画面。
合成方案的参数可以参考这张表:
| 参数 | 建议值 | 目的 |
|---|---|---|
| 渲染分辨率 | 1920x1080 | 匹配现场工业相机 |
| 相机高度 | 0.4m到1.5m随机 | 覆盖叉臂视角与顶装视角 |
| 货架/托盘模型 | 2-3种模型多贴图 | 打破单一纹理 |
| 光照环境 | HDR室内环境光+模拟窗光 | 覆盖逆光与昏暗 |
| AGV运动路径 | 手动铺设路线+随机停顿 | 生成交汇与遮挡帧 |
合成数据在3D引擎里生成时标注是精确的,省去了大量人工标注成本,但分布天然比真实场景“干净”,全量混入会把模型对真实纹理的敏感度带偏。我的经验是合成样本不超过训练集总量的两成,并严格只把它放入train,val必须全部保留真实场景采样,否则验收指标会被合成样本拉出虚高。
部署前的最终验证,我的习惯是先在工控机上跑一次ONNX导出后的推理,而不是在训练机上用PyTorch验证。AGV调度系统通常要求视觉输出频率不低于10Hz,模型在训练卡上能达到50ms,换到Jetson上可能直接掉到120ms。让模型跑一段实拍视频,统计每类的误检率、漏检率、平均推理耗时,输出一张验收表格。验收表里如果记录到“val mAP 98%但实拍掉了18个点”,这类问题九成指向数据分布偏差,剩下的一成才是量化精度损失。先验证数据集,再验证模型,不要一上来就怀疑芯片。
我做这类项目有个习惯:每次训练前先跑一遍数据体检脚本,把train/val交叉、类别分布直方图、可视化抽查图这三样东西打印出来贴到项目文档里。模型指标不达标的时候,先翻这三份材料,再决定是回数据还是动模型。把数据验证当成例行流程之后,翻车的次数明显少了,希望帮到你。
本文还有配套的精品资源,点击获取