货架空缺检测数据集:4470张双格式标注与YOLOv8实战

发布时间:2026/10/11 20:48:35
货架空缺检测数据集:4470张双格式标注与YOLOv8实战 简介本资源为面向零售智能化与计算机视觉方向的超市货架空置缺货检测数据集适用于目标检测模型训练、货架陈列分析及补货预警等场景适合具备一定深度学习基础的研究者与算法工程师使用。数据集共4470张jpg图片每张均配有对应的VOC格式xml标注与YOLO格式txt标注标注类别为Empty-Space与Reduced两类分别对应货架空置与商品减少状态总标注框数达23775个其中Empty-Space框7570个、Reduced框16205个采用labelImg工具按矩形框规则完成标注。压缩包内文件总数2000个以xml标注文件为主另含说明文件整体约251.17MB目录结构便于按图片与标注对应检索。目前已有380人学习下载可为货架缺货识别、商品陈列监测等任务提供较为充足的标注样本帮助读者快速构建训练与验证流程。1. 货架空缺检测数据集4470 张双格式标注补货巡检的第一块砖做零售巡检的兄弟大概率都遇到过这个场景老板要一套自动识别货架空缺的方案你兴冲冲搭完 YOLO 训练环境结果卡在数据上——网上公开的货架数据集要么是商品分类要么是货架层识别真正标了「空位」这个类别的少得可怜。这份 4470 张的超市商品货架空置缺货检测数据集就是冲着这个缺口来的。它把货架上的「空缺区域」和「正常商品区域」分成两类做标注同时提供 VOC 和 YOLO 两种格式意味着你拿到手不用再折腾格式转换直接能喂给 YOLOv5/v8 或者 Faster R-CNN 这类主流检测框架。适合谁做智慧零售巡检、自动补货提醒、货架陈列合规检查的团队以及想拿真实场景数据跑通检测流程的个人开发者。一句话它解决的是「有场景、有需求、没标注数据」这个最卡脖子的问题。2. 数据集拆解4470 张图、2 类标签、VOC 与 YOLO 双格式到底怎么选2.1 两类标签的定义与标注边界这份数据集的核心是 2 类标签。虽然项目标题没有展开写具体类名但按货架空缺检测的通用做法通常是empty空缺/空位和product商品/满陈列两类或者vacancy与normal。标注方式是在货架区域画矩形框把「本该有商品但空着的位置」框出来同时把「有商品的位置」也框出来形成对比。这里有个容易被忽略的点空缺区域的边界怎么定是框到货架层板的边缘还是框到相邻商品的边缘不同标注习惯会直接影响模型学到的特征。我一般会先抽 20 张图用标注工具打开看框的贴合程度——如果空缺框普遍贴到层板边缘说明标注者倾向于「物理空间」定义如果框只覆盖商品消失后留下的间隙那更偏向「视觉差异」定义。这个判断决定了你后续要不要做框的裁剪或扩展。提示拿到数据集先别急着训练用标注查看工具过一遍框的分布比看任何说明文档都管用。2.2 VOC 与 YOLO 格式的差异与选用逻辑VOC 格式每张图对应一个 XML 文件里面记录filename、size、每个目标的bndboxxmin/ymin/xmax/ymax和name。YOLO 格式则是每张图一个 txt每行class_id x_center y_center width height坐标全部归一化到 0~1。选哪个取决于你的训练框架格式适用框架坐标类型每图文件数VOCFaster R-CNN、SSD、MMDetection绝对像素1 个 XMLYOLOYOLOv5/v8/v11、YOLOX归一化1 个 txt如果你用 Ultralytics 的 YOLO 系列直接走 YOLO 格式省掉转换步骤。如果要用 MMDetection 或 Detectron2VOC 格式更顺手。两种格式同时提供的好处是你可以用同一批图做框架对比实验不用因为格式问题重标一遍。2.3 目录结构与文件命名规范一个规范的检测数据集目录通常长这样dataset/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── data.yamlVOC 格式则可能是dataset/ ├── JPEGImages/ ├── Annotations/ └── ImageSets/ └── Main/ ├── train.txt └── val.txt拿到压缩包后第一件事是确认目录层级。有些数据集会把图片和标注混在一起或者 train/val 已经分好但命名不统一。我一般会跑一段脚本统计图片数量和标注文件数量是否一致差一个都说明有问题。import os img_dir dataset/images label_dir dataset/labels imgs set(os.path.splitext(f)[0] for f in os.listdir(img_dir) if f.endswith((.jpg, .png))) labels set(os.path.splitext(f)[0] for f in os.listdir(label_dir) if f.endswith(.txt)) print(图片数:, len(imgs)) print(标注数:, len(labels)) print(有图无标注:, imgs - labels) print(有标注无图:, labels - imgs)这段脚本做的是集合差运算。imgs - labels找出有图但没标注的样本labels - imgs反过来。正常情况两个差集都应该是空的。如果有图无标注要么是漏标要么是负样本但检测任务一般不用纯负样本图如果有标注无图直接删掉对应标注文件。2.4 训练集与验证集的划分建议如果数据集已经分好 train/val直接用。如果没分按 8:2 或 7:3 切。货架空缺检测有个特殊性同一货架、同一角度拍的多张图如果被分到 train 和 val 两边验证指标会虚高。正确做法是按「货架 ID」或「拍摄批次」划分而不是随机按图划分。我一般会这样做先按文件名前缀或拍摄时间分组确保同一组的图只出现在一个集合里。如果数据集没有提供分组信息至少用train_test_split时加random_state固定种子保证可复现。from sklearn.model_selection import train_test_split import os all_imgs [f for f in os.listdir(dataset/images) if f.endswith(.jpg)] train, val train_test_split(all_imgs, test_size0.2, random_state42) with open(train.txt, w) as f: f.write(\n.join(train)) with open(val.txt, w) as f: f.write(\n.join(val))test_size0.2表示验证集占 20%random_state42保证每次运行划分结果一致。生成的 txt 文件可以给 VOC 格式的ImageSets/Main用也可以改造成 YOLO 的data.yaml里的路径列表。3. 从零跑通训练YOLOv8 与 Faster R-CNN 两条路线3.1 用 YOLO 格式直接训练 YOLOv8YOLOv8 对数据目录的要求很明确images/train、images/val、labels/train、labels/val四个文件夹外加一个data.yaml。data.yaml内容如下path: ./dataset train: images/train val: images/val names: 0: empty 1: productpath是数据集根目录train和val是相对路径。names里的类别顺序必须和标注文件里的class_id对应——如果标注时empty是 0、product是 1这里就不能写反。训练命令yolo detect train datadataset/data.yaml modelyolov8n.pt epochs100 imgsz640 batch16modelyolov8n.pt用的是 nano 版本适合先跑通流程。epochs100对 4470 张图来说偏多实际 50~80 轮就能看到收敛趋势。imgsz640是输入分辨率货架图如果远景多、空缺区域小可以提到 1280但显存占用会翻倍。batch16根据显卡调整8G 显存跑 640 分辨率大概能到 16跑 1280 就只能降到 4 或 8。训练过程中重点看mAP50和mAP50-95两个指标。货架空缺检测里empty类的召回率比精确率更重要——漏检一个空缺补货员就少跑一趟误检一个最多白跑一趟。所以如果empty的 recall 偏低优先调低置信度阈值或增加正样本权重。3.2 用 VOC 格式训练 Faster R-CNN如果走 MMDetection 路线VOC 格式需要先转成 COCO 或自定义 Dataset。MMDetection 支持 VOC 数据集配置里指定ann_file和img_prefix即可。核心配置片段dataset_type VOCDataset data_root dataset/ train_pipeline [ dict(typeLoadImageFromFile), dict(typeLoadAnnotations, with_bboxTrue), dict(typeResize, scale(1333, 800), keep_ratioTrue), dict(typeRandomFlip, flip_ratio0.5), dict(typePackDetInputs) ]Resize的scale(1333, 800)是 Faster R-CNN 的经典设置短边缩到 800长边不超过 1333。RandomFlip做水平翻转增强货架图翻转后语义不变可以用。但垂直翻转要慎用——货架倒过来不符合物理常识可能引入噪声。训练启动python tools/train.py configs/voc/faster_rcnn_r50_fpn.pyFaster R-CNN 比 YOLO 慢4470 张图在单卡上可能要跑几个小时。好处是小目标检测更稳如果空缺区域在图中占比很小Faster R-CNN 的 RPN 阶段能更好地召回。3.3 关键超参数怎么调参数YOLOv8 推荐值Faster R-CNN 推荐值说明输入尺寸640 / 12801333×800小目标多就加大batch size16 / 82 / 4看显存学习率0.010.02大 batch 可线性放大置信度阈值0.250.3推理时调NMS IoU0.450.5密集框可调低置信度阈值和 NMS IoU 是推理阶段的参数训练时不用设。但训练完后一定要在验证集上扫一遍这两个值找召回率和精确率的平衡点。货架空缺场景我一般会把置信度阈值压到 0.2 左右宁可多框几个也别漏。3.4 训练日志怎么看YOLOv8 的日志会输出box_loss、cls_loss、dfl_loss和mAP。box_loss下降说明框回归在收敛cls_loss下降说明分类在学。如果box_loss震荡不降检查标注框是否有越界或宽高为 0 的情况。如果cls_loss降不下去可能是两类样本极度不平衡——货架图里product框远多于empty框这时候要么加empty的采样权重要么用 focal loss。Faster R-CNN 的日志重点看loss_rpn_cls、loss_rpn_bbox、loss_cls、loss_bbox。RPN 的两个 loss 先收敛然后才是 ROI 头的 loss。如果 RPN loss 一直很高说明 anchor 尺度和目标尺寸不匹配需要调anchor_generator的scales和ratios。4. 避坑与排查标注、格式、训练里最容易翻车的五件事4.1 标注框越界或宽高为负现象训练时报AssertionError: x1 x2或 YOLO 加载标注时提示坐标超出 0~1 范围。原因VOC 转 YOLO 时如果xmax小于xmin或者框超出图片边界归一化后就会出现负值或大于 1 的值。手工标注时拖拽方向不同也会导致坐标顺序颠倒。解决写一个清洗脚本遍历所有标注文件把xmin xmax的交换把超出边界的裁剪到[0, width]和[0, height]。YOLO 格式则检查每行后四个值是否在 0~1 之间超出就 clamp。def clamp_yolo_line(line): parts line.strip().split() cls_id parts[0] x, y, w, h map(float, parts[1:]) x max(0, min(1, x)) y max(0, min(1, y)) w max(0, min(1, w)) h max(0, min(1, h)) return f{cls_id} {x:.6f} {y:.6f} {w:.6f} {h:.6f}max(0, min(1, x))把值限制在 0 到 1 之间。:.6f保留六位小数避免精度丢失。4.2 类别 ID 从 1 开始导致训练报错现象YOLO 训练时提示Label class 2 exceeds nc2或类似错误。原因VOC 的类别通常从 1 开始编号而 YOLO 要求从 0 开始。转换时如果直接拿 VOC 的name映射到class_id容易把empty映射成 1、product映射成 2但data.yaml里只写了 0 和 1。解决转换脚本里显式定义类别映射字典确保从 0 开始。转换后抽查几个 txt 文件确认最大class_id等于nc - 1。4.3 图片和标注文件名不一致现象训练时提示找不到标注文件或者某张图被跳过。原因图片是IMG_001.jpg标注是IMG_001.xml或IMG_001.txt但中间可能多了空格、大小写不一致、或者扩展名不同。批量重命名时容易出这个问题。解决统一用os.path.splitext取文件名主干做匹配不要硬编码扩展名。转换前先跑一遍 2.3 节的统计脚本确认差集为空。4.4 验证集指标虚高现象验证集mAP很高但实际部署后漏检严重。原因同一货架的多张图被分到了 train 和 val 两边模型在验证集上看到的是「见过的货架」不是「没见过的货架」。解决按货架 ID 或拍摄批次分组划分。如果数据集没提供分组信息至少按文件名前缀分组——同一批拍摄的图通常有相同前缀。4.5 小目标空缺检测召回低现象大块空缺能检出小空隙漏检。原因输入分辨率不够或者 anchor 尺度偏大。货架远景图中一个空缺可能只占几十个像素。解决把imgsz从 640 提到 1280或者在 YOLO 里加一个更小的 anchor。Faster R-CNN 则调小anchor_scales的最小值。另外可以在数据增强里加mosaic和copy-paste人为增加小目标样本。5. 进阶技巧用切片推理和类别权重把召回再拉一截训练跑通只是及格线真正上线前还有两件事值得做切片推理和类别权重调整。切片推理SAHI的思路是把大图切成重叠的小块分别检测后再合并。货架图通常分辨率高、目标密集直接缩到 640 会丢小目标。用 SAHI 把图切成 640×640 的块重叠 20%每块单独推理最后用 NMS 合并。实测在货架空缺场景下小空缺的召回能提升 10~15 个百分点。代价是推理速度变慢适合离线巡检不适合实时视频流。from sahi import AutoDetectionModel from sahi.predict import get_sliced_prediction model AutoDetectionModel.from_pretrained( model_typeyolov8, model_pathruns/detect/train/weights/best.pt, confidence_threshold0.2, devicecuda:0 ) result get_sliced_prediction( shelf.jpg, model, slice_height640, slice_width640, overlap_height_ratio0.2, overlap_width_ratio0.2 )slice_height和slice_width是切片尺寸overlap_*_ratio是重叠比例。重叠太小会漏掉跨块目标太大则重复框多、NMS 压力大。0.2 是个比较稳的起点。类别权重方面如果empty类样本远少于product可以在损失函数里给empty加权。YOLO 不直接暴露类别权重参数但可以通过复制empty样本或使用focal loss来间接平衡。Faster R-CNN 则可以在CrossEntropyLoss里传class_weight。验证方法上我习惯在验证集上画 PR 曲线分别看两类。如果empty的曲线在 recall 0.8 时 precision 掉到 0.5 以下说明阈值设高了往下调。如果 precision 一直很高但 recall 上不去说明模型没学到empty的特征得回头查标注质量。从那以后我每次拿到新数据集都强制走一遍「统计差集 → 抽查标注 → 分组划分 → 小分辨率试跑 → 看 PR 曲线」这套流程少一步都可能在后头翻车。希望帮到你。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询