ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

基于YOLOv8的仓库货物盘点系统:从数据集到部署全流程实战

基于YOLOv8的仓库货物盘点系统:从数据集到部署全流程实战 简介这份资源面向计算机、人工智能、自动化等专业的在校学生与教师提供一套可直接运行的仓库货物盘点系统基于YOLOv8目标检测实现货物识别与计数适合作为毕业设计、课程设计或大作业的完整方案。压缩包共97个文件约24.21MB以70个Python源码文件为核心辅以4个pt模型权重、5个xml配置、12个pyc缓存及mp4演示视频等覆盖模型训练、推理检测与可视化界面等模块。资源包含源码、完整数据集、可视化页面和部署说明可生成核心指标曲线图、混淆矩阵、F1分数曲线、精确率-召回率曲线、验证集预测结果及标签分布图并附有README说明与训练脚本便于快速复现与二次修改。目前已有48人学习下载适合希望低成本完成目标检测项目实践、积累工程经验的读者参考使用。1. 从一张货架照片说起YOLOv8 仓库货物盘点系统到底解决什么问题做过仓库盘点的人都懂那种崩溃拿着纸质清单一排排货架对过去眼睛看花了还容易漏。更麻烦的是盘点结果要手工录进 Excel隔天再核对一遍错一个数字就得从头查。这套《基于 YOLOv8 的仓库货物盘点系统》想干的事很直接——用摄像头拍一张货架照片模型自动框出每一件货物、数出数量、标出类别再通过一个可视化界面把结果呈现出来最后给一份能直接跑的部署教程。它适合两类人一类是毕设或课程设计需要完整闭环源码、数据集、界面、部署文档齐全的学生另一类是中小仓库想低成本试水视觉盘点的工程师。核心链路其实就四段数据集准备、YOLOv8 训练、推理服务封装、可视化界面调用。后面几章我会按这个顺序把每一步的参数、坑和验证方法讲清楚让你拿到这套东西之后不是「能跑」而是「知道为什么这么跑」。2. 数据集怎么准备从货架照片到 YOLOv8 能吃的标签2.1 仓库货物数据集和通用数据集的差别在哪很多人第一反应是拿 COCO 或 ImageNet 凑合但仓库场景和这些通用数据集差得很远。COCO 里的「瓶子」「盒子」是生活场景光照均匀、背景干净仓库里是密集堆叠、遮挡严重、同类货物外观高度相似甚至同一排货架上几十个箱子长得一模一样。如果你直接拿 COCO 预训练权重去推理货架图模型会把整排货架当成一个「大物体」或者把相邻两个箱子合并成一个框。所以这套系统自带的数据集价值就在这里它是按仓库实际拍摄角度、光照和堆叠方式标注的类别定义也贴合盘点需求比如按 SKU 或按货物类型分。常见做法是先用自带数据集跑通全流程再逐步替换成你自己仓库的照片。替换时不要一次性全换先换 20% 做增量训练观察 mAP 变化稳定后再扩大比例。这样能避免「新数据把旧类别带偏」的翻车。2.2 标注格式转换把 VOC 转成 YOLO 格式的脚本与四个边界坑自带数据集如果是 VOC 格式XML 标注YOLOv8 不认必须转成 YOLO 的 txt 格式。转换逻辑不复杂但边界情况特别多。下面这个脚本是我常用的版本处理了四个容易出问题的地方。import os import xml.etree.ElementTree as ET from PIL import Image # 类别映射必须和 data.yaml 里的 names 顺序一致 CLASS_MAP {box: 0, bottle: 1, package: 2} def voc_to_yolo(xml_dir, img_dir, out_dir): os.makedirs(out_dir, exist_okTrue) for xml_file in os.listdir(xml_dir): if not xml_file.endswith(.xml): continue tree ET.parse(os.path.join(xml_dir, xml_file)) root tree.getroot() # 坑1图片尺寸要从实际图片读不能信 XML 里的 size有些标注工具写错 img_name root.find(filename).text img_path os.path.join(img_dir, img_name) with Image.open(img_path) as im: w, h im.size lines [] for obj in root.findall(object): cls_name obj.find(name).text if cls_name not in CLASS_MAP: continue # 坑2忽略未定义类别否则训练时报 index 越界 bbox obj.find(bndbox) xmin float(bbox.find(xmin).text) ymin float(bbox.find(ymin).text) xmax float(bbox.find(xmax).text) ymax float(bbox.find(ymax).text) # 坑3坐标裁剪到图像范围内标注越界会导致归一化后为负 xmin, ymin max(0, xmin), max(0, ymin) xmax, ymax min(w, xmax), min(h, ymax) if xmax xmin or ymax ymin: continue # 坑4宽高为0的无效框直接丢弃 xc (xmin xmax) / 2.0 / w yc (ymin ymax) / 2.0 / h bw (xmax - xmin) / w bh (ymax - ymin) / h lines.append(f{CLASS_MAP[cls_name]} {xc:.6f} {yc:.6f} {bw:.6f} {bh:.6f}) out_file os.path.join(out_dir, xml_file.replace(.xml, .txt)) with open(out_file, w) as f: f.write(\n.join(lines)) voc_to_yolo(datasets/annotations, datasets/images, datasets/labels)逻辑说明遍历 XML读图片真实尺寸把绝对坐标转成归一化的中心点加宽高。参数上CLASS_MAP必须和后续data.yaml的names严格对应顺序错了模型学到的类别就是乱的。四个坑分别是尺寸来源、未定义类别、坐标越界、无效框。转换完建议随机抽 10 张用可视化脚本画框检查一遍别嫌麻烦这一步省了后面训练 loss 不降你会更头疼。2.3 数据集划分与 data.yaml 的写法YOLOv8 要求按images/train、images/val、labels/train、labels/val组织。划分比例一般 8:2如果样本少于 500 张建议 7:3 并做交叉验证。data.yaml写法如下path: ./datasets train: images/train val: images/val nc: 3 names: [box, bottle, package]nc是类别数names顺序必须和转换脚本里的CLASS_MAP一致。这里没有test字段因为盘点系统最终是在真实货架上验证留一个独立测试集意义不大不如把验证集调参调好。3. YOLOv8 训练参数怎么设、损失曲线怎么看、显存不够怎么办3.1 环境配置与最小训练命令环境这块Python 3.8 到 3.10 都行PyTorch 装对应 CUDA 版本。如果你用的是 GTX 1660 Ti 这类 6G 显存的卡别一上来就yolov8l直接yolov8n或yolov8s。最小训练命令yolo detect train \ datadatasets/data.yaml \ modelyolov8n.pt \ epochs100 \ imgsz640 \ batch8 \ device0 \ projectruns/train \ namewarehouse_v1参数说明modelyolov8n.pt是加载预训练权重仓库货物数据集通常几千张从头训不如微调imgsz640是输入分辨率货架图如果货物很小可以提到 960但显存翻倍batch8是 6G 显存的保守值显存够可以加到 16epochs100配合早停默认 patience50基本够用。训练开始后看runs/train/warehouse_v1/results.csv重点关注metrics/mAP50-95和train/box_loss。3.2 损失函数曲线怎么读三种典型形态对应的调参动作YOLOv8 训练完会自动生成损失曲线图但很多人只看最后数值不看形态。三种典型情况第一种box_loss和cls_loss都平稳下降mAP稳步上升这是正常收敛不用动。第二种box_loss下降但cls_loss震荡说明分类头学不动常见原因是类别不平衡或标注里同一类货物标法不一致解决方法是检查标注、对少样本类别做过采样。第三种两个 loss 都下降但mAP卡在低位大概率是验证集和训练集分布差异大比如训练集是白天货架、验证集混了夜间图这时候要么补夜间数据要么重新划分。画曲线的脚本可以用 pandas 读results.csv再 matplotlib 画也可以直接用yolo detect train输出目录里的results.png。我一般会把results.csv拷出来自己画方便对比多次实验。3.3 显存不够时的四个降级手段6G 显存跑 640 分辨率、batch8 通常没问题但如果你的货物图分辨率高或者类别多可能会 OOM。降级顺序建议先把batch降到 4再把imgsz降到 512然后换更小的模型yolov8n最后才考虑ampFalse关闭混合精度反而更省显存但慢。不要一上来就改模型结构那是最后手段。另外workers设太大也会占内存Linux 下设 8Windows 下设 0 或 2否则容易卡在数据加载。4. 推理服务与可视化界面从模型文件到能点的按钮4.1 用 FastAPI 封装推理接口的最小实现训练完得到best.pt下一步是让界面能调用。常见做法是用 FastAPI 包一层 HTTP 接口界面发图片、接口返回框和数量。最小实现from fastapi import FastAPI, UploadFile, File from ultralytics import YOLO import numpy as np from PIL import Image import io app FastAPI() model YOLO(runs/train/warehouse_v1/weights/best.pt) app.post(/predict) async def predict(file: UploadFile File(...)): img_bytes await file.read() img Image.open(io.BytesIO(img_bytes)).convert(RGB) results model(np.array(img), conf0.4, iou0.5) boxes results[0].boxes detections [] for box in boxes: detections.append({ cls: int(box.cls), conf: float(box.conf), xyxy: box.xyxy.tolist()[0] }) return {count: len(detections), detections: detections}逻辑说明接口接收上传图片转成 numpy 数组送进模型conf0.4是置信度阈值低于这个值的框不输出iou0.5是 NMS 的 IoU 阈值控制重叠框合并。返回里带count就是盘点数量detections给界面画框用。参数上conf调高会漏检、调低会误检仓库场景建议 0.35 到 0.5 之间试iou在货物密集堆叠时可以降到 0.4避免相邻货物被合并。4.2 可视化界面怎么接三个必须对齐的字段界面不管是 PyQt、Gradio 还是 Web 前端核心是对齐三个字段图片路径或二进制、接口返回的detections、以及数量展示。常见翻车点是界面显示的框和图片尺寸不匹配——接口返回的坐标是基于原图的界面如果先把图片缩放了再画框就会错位。解决办法是界面画框前把坐标按缩放比例还原或者干脆让接口返回缩放后的坐标。另一个坑是并发多个用户同时上传模型实例如果没做线程安全会报错。简单做法是加锁或者用model.predict的批处理模式。4.3 部署到 RK3588 这类边缘设备的注意点热词里有人问 RK3588 部署 YOLOv8这里说下思路。RK3588 有 NPU但 YOLOv8 的 PyTorch 模型不能直接跑需要转成 ONNX 再转 RKNN。转换时注意imgsz要和训练时一致否则精度掉得厉害量化校准集要用仓库真实图片别用 COCO 的图否则量化后小目标检测会崩。转完在板子上跑推理速度能到几十毫秒但后处理NMS如果放在 CPU 上会成为瓶颈建议用 RKNN 自带的后处理或自己写 C 版本。5. 避坑与排查盘点系统上线前必须过的五道坎5.1 现象模型在验证集 mAP 很高实际货架图却漏检严重原因验证集和实际场景分布不一致比如验证集是摆拍图实际是监控角度、有畸变。解决从实际摄像头截 50 张图重新标注加入训练集做增量训练同时把imgsz提到和实际分辨率匹配。5.2 现象同一件货物被框出两个框原因NMS 的iou阈值设太高或者货物本身有多个可识别部分。解决把iou从 0.5 降到 0.4如果还不行检查标注里是不是把一件货物标成了两个框标注不一致会让模型学出重复检测。5.3 现象训练 loss 突然变成 NaN原因学习率太大或者数据里有坏图尺寸为 0、通道数不对。解决先把lr0从 0.01 降到 0.001再用脚本遍历所有图片检查Image.open是否报错坏图直接删掉。5.4 现象界面点「盘点」按钮没反应后台也没日志原因接口跨域被拦或者前端请求地址写成了localhost但服务部署在另一台机器。解决FastAPI 加 CORSMiddleware前端地址改成实际 IP用浏览器 F12 看 Network 面板的报错。5.5 现象RK3588 上推理结果和 PC 上差很多原因量化精度损失或者输入预处理归一化、通道顺序不一致。解决先用 ONNX 在 PC 上验证和 PyTorch 结果一致再转 RKNN量化时校准集至少 200 张真实图预处理严格按训练时的mean和std来。6. 把盘点数量做准的一个技巧按类别分组计数与置信度过滤最后一章说个具体技巧。很多人拿到这套系统后发现总数量对了但分类数量经常错——比如把「箱子」数成了「包裹」。问题出在计数逻辑上直接统计detections长度会把低置信度的误检也算进去。我的做法是分两步先按类别分组再对每组做置信度过滤和面积过滤。def count_by_class(detections, conf_thres0.45, min_area500): counts {} for det in detections: if det[conf] conf_thres: continue x1, y1, x2, y2 det[xyxy] area (x2 - x1) * (y2 - y1) if area min_area: continue # 过滤掉过小的误检框 cls det[cls] counts[cls] counts.get(cls, 0) 1 return counts参数上conf_thres比接口的conf再高一点因为接口为了画框会保留低置信度框但计数要严min_area根据实际货物在图片里的像素面积设一般取平均货物面积的 1/3。这个技巧在货物密集堆叠时特别有用能把误检导致的虚高数量压下去。验证方法拿 20 张有标注的货架图人工数一遍真实数量再用这个函数跑一遍对比误差。如果某类误差超过 10%回去看是漏检还是误检漏检就降conf误检就升conf或加面积过滤。我自己的习惯是每次调整完参数都把对比结果记在一个表格里攒够 5 次再决定要不要重新训练。这套系统值不值得做取决于你能不能把「数得准」这件事量化验证出来而不是跑通界面就完事。希望帮到你。本文还有配套的精品资源点击获取
返回列表