☰
基于 YOLO11 的超市货架空位智能巡检系统 | 源码系统分享
2026/10/11 5:01:27 网站建设 项目流程

基于 YOLO11 的超市货架空位智能巡检系统

关键词:YOLO11 · 智能零售 · 货架巡检 · 缺货预警 · Streamlit
模型最佳 mAP@0.5 =93.8%,单图推理 < 50 ms,自动锁定"画面里所有空货位"。


一、背景

1.1 行业痛点

线下零售门店的运营效率,很大程度上取决于"补货是否及时"。一个常见但容易被低估的场景:

  • 货架上爆款被一抢而空 →空货位停留时间越长,营业额损失越大;
  • 价签还在、商品没了 → 顾客以为"售完不卖了",扭头走人;
  • 大店动辄几千个 SKU,人工巡店一圈半小时起步,信息回传到补货已经是 20 分钟以后。

传统方案靠"巡店员 + 钉钉拍照 + 微信群报修",问题很明显:依赖人力、响应滞后、夜班漏检高。本项目用 YOLO11n 把这件事变成一次"上传图片 → 自动框出空位 → 推送补货工单"的工程化流程。

视频演示与源码下载

https://www.bilibili.com/video/BV1Fgph67EQy/


包含:
📦完整项目源码
📦预训练模型权重
🗂️数据集

1.2 项目运行效果

Web 界面总览(巡检台):

单张巡店图检测——画面里所有空货位一次性框出:

1.3 项目介绍

项目定位:面向超市/便利店/仓储零售的智能货架巡检 Demo,识别画面中所有"货架空位"区域,输出可追溯的检测明细,辅助补货与陈列复核。

核心功能:

模块说明
单图检测上传一张巡店图,自动框出全部空货位
批量图片多张/ZIP 一次性上传,自动统计"每张图空位数 + 全店总缺位数"
视频流检测适配巡检机器人/监控录像逐帧分析,输出时间轴趋势
摄像头实时直接调用门店摄像头,做"实时缺货预警"

类别定义:本数据集是单类别检测任务(nc=1),目标只有一个——“空”(empty_shelf / 货架空位)。在 UI 中通过class_display_names把英文标签映射成中文"货架空位",更贴近门店运营人员的用语。

技术栈:

层选型
检测模型Ultralytics YOLO11n(轻量化骨干)
推理引擎PyTorch + Ultralytics
前端/交互Streamlit(响应式 UI + CSS 主题化)
视频处理OpenCV + ImageIO-FFmpeg
图表分析Streamlitbar_chart/line_chart+ pandas
配置驱动PyYAML(configs/project.yaml)

项目创新点:

  1. 单类高召回是核心 KPI——空货位检测最怕"漏"(漏一个就少一次补货机会),项目主调 IoU=0.7 + conf=0.25 的组合,先保召回,再用 NMS 收敛;
  2. 配置驱动的行业话术——同一份代码骨架在火灾/PCB/口罩等场景都能复用,只换project.yaml和数据集即可;
  3. 批量页 = 巡店报告——批量上传后自动出"每图目标数"和"类别分布"双图,等价于"门店补货排序表",店长可以直接对照补货。

二、设计框架

2.1 系统总体架构

┌──────────────────────────────────────────────────────────────┐ │ 浏览器(Streamlit 巡检台) │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │ │ │ 单图上传 │ │ 批量上传 │ │ 视频/摄像头 │ │ │ └──────┬──────┘ └──────┬──────┘ └──────────┬──────────┘ │ └──────────┼─────────────────┼─────────────────────┼────────────┘ │ │ │ ┌──────────▼─────────────────▼─────────────────────▼────────────┐ │ Streamlit 服务端(streamlit_app.py) │ │ ┌─────────────────┐ ┌──────────────────┐ ┌───────────────┐ │ │ │ load_yaml/UI │ │ infer_image_path │ │ batch 聚合分析 │ │ │ └─────────────────┘ └──────────────────┘ └───────┬───────┘ │ └──────────────────────────────────────────────────────┼─────────┘ │ ┌──────────────────────────────────────────────────────▼─────────┐ │ YOLO11 推理引擎(ultralytics + PyTorch) │ │ YOLO("model/best.pt").predict(img, conf=0.25, iou=0.7) │ │ → boxes(xyxy/cls/conf) + result.plot()(标注 BGR ndarray) │ └────────────────────────────────────────────────────────────────┘

2.2 YOLO11 网络结构

Input (640×640×3 巡店图) │ ▼ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ Backbone │ → │ Neck │ → │ Head │ │ C3k2 + SPPF │ │ FPN + PAN │ │ Decoupled + │ │ + C2PSA 注意力│ │ (多尺度融合) │ │ DFL │ └──────────────┘ └──────────────┘ └──────┬───────┘ │ ▼ [类别概率 + 边框坐标 + 置信度]

YOLO11n 相比 v8n 的关键变化:

  • C3k2 模块替换 C2f,参数更少、感受野更灵活;
  • C2PSA 注意力提升对货架"形状不规则空白区"的特征显著性;
  • 解耦头 + DFL让边框回归走分布化预测,对货架空位这种"边界模糊"目标更稳。

2.3 检测流程

原始巡店图(手机拍/巡检机器人) ↓ Letterbox 缩放 640×640,保持长宽比 ↓ Backbone 抽取 P3/P4/P5 三层特征 ↓ Neck FPN+PAN 多尺度融合 ↓ Head 输出 [bbox + cls_prob] ↓ conf ≥ 0.25 过滤 + NMS(iou=0.7) ↓ result.plot() 渲染标注图 ↓ Streamlit 双列展示 + 表格 + bar_chart 聚合

三、代码结构(核心 50 行 + 解析)

项目目录约定:

超市货架空位检测/ ├── app/streamlit_app.py # Web 入口 ├── configs/project.yaml # 行业话术 + UI + 推理参数 ├── model/best.pt # 训练好的 YOLO11n 权重 ├── scripts/ # 训练/评测/导出脚本 ├── 超市空货架检测train_CH_yolo11n/ # 训练产物 └── 超市空货架检测数据集/ # 1500 张标注图 + data.yaml

核心 50 行:模型加载 + 单图推理 + Streamlit 单图分支

frompathlibimportPathimportstreamlitasst,pandasaspd,yamlfromultralyticsimportYOLO PROJECT_ROOT=Path(__file__).resolve().parent.parent CFG=yaml.safe_load((PROJECT_ROOT/"configs/project.yaml").open(encoding="utf-8"))APP_META=CFG.get("app",{})CLASS_DISPLAY=APP_META.get("class_display_names")or{}# empty_shelf → 货架空位MODEL_PATH=PROJECT_ROOT/"model"/"best.pt"DEFAULT_CONF=float(CFG.get("inference",{}).get("conf",0.25))@st.cache_resource(show_spinner=False)defload_model(model_path:str)->YOLO:returnYOLO(model_path)# 仅首次加载,6 MB 量级,命中缓存后零延迟definfer_image_path(model:YOLO,image_path:Path,conf:float):"""单图推理:返回 (RGB 标注图, 检测明细 DataFrame)"""result=model.predict(str(image_path),conf=conf,verbose=False)[0]annotated=result.plot()# BGR ndarray,已画好框 + 类别 + 置信度rows=[]ifresult.boxesisnotNone:forboxinresult.boxes:cls_id=int(box.cls.item())raw_name=result.names[cls_id]# 训练原标签display=CLASS_DISPLAY.get(raw_name,raw_name)# → 中文"货架空位"x1,y1,x2,y2=[float(v)forvinbox.xyxy[0].tolist()]rows.append({"class_id":cls_id,"class_name":raw_name,"display":display,"confidence":round(float(box.conf.item()),4),"x1":round(x1,1),"y1":round(y1,1),"x2":round(x2,1),"y2":round(y2,1),})returnannotated[:,:,::-1],pd.DataFrame(rows)# BGR → RGB# ───────── Streamlit 单图分支 ─────────conf=st.slider("置信度阈值",0.01,0.99,DEFAULT_CONF,0.01)model=load_model(str(MODEL_PATH))uploaded=st.file_uploader("上传巡店图片",type=["jpg","png","bmp","webp"])ifuploadedisnotNone:importtempfilewithtempfile.NamedTemporaryFile(delete=False,suffix=".jpg")asf:f.write(uploaded.getvalue());tmp=Path(f.name)annotated_img,df=infer_image_path(model,tmp,conf)col1,col2=st.columns(2)col1.image(uploaded.getvalue(),caption="原图",width="stretch")col2.image(annotated_img,caption="检测结果",width="stretch")st.metric("画面空货位数",len(df))st.dataframe(df,width="stretch")

逐段解析:

  1. class_display_names把英文映射成中文—— 巡检台直接给店长看,所以训练标签是empty_shelf,UI 上是货架空位,运营无感切换。
  2. @st.cache_resource缓存模型—— Streamlit 每次交互都会重跑脚本,没缓存会反复加载 6 MB 权重,体验掉到 5s 以上。
  3. model.predict(...)一次返回结构化结果——boxes.xyxy/boxes.cls/boxes.conf全部 tensor,遍历转 DataFrame,下游图表/CSV/批量分析复用同一份 schema。
  4. result.plot()自带 BGR 标注图—— 不需要手动cv2.rectangle,颜色和置信度文字 Ultralytics 已经画好。
  5. 单类项目的关键指标是"画面空货位数"—— 用st.metric(len(df))突出展示,店长一眼就能看出"这张图缺几个位"。

四、训练效果

4.1 训练总览

数据集:1500 张真实超市场景图,按 train/val/test 划分(约 1400 / 97 / 50),单类目标。训练参数:yolo11n.pt→ 200 epoch、imgsz=640、batch=16。

训练 loss / P / R / mAP 曲线:

最终指标(results.csv最后一行):

指标数值含义
Precision §0.928检出框 92.8% 是真的空货位(误报低)
Recall ®0.887真实空货位 88.7% 被找回(漏检低)
mAP@0.50.938IoU=0.5 下综合表现,工业可用
mAP@0.5:0.950.719严格 IoU 区间仍稳健

4.2 PR 曲线

单类任务的 PR 曲线整体压在右上角且非常平滑,说明模型在大部分置信度阈值下都能保持高精度和高召回。

4.3 归一化混淆矩阵

单类项目的混淆矩阵主要看"目标 ↔ 背景"两个方向。本项目对角线非常显著,说明模型在区分"空货位"和"背景纹理(包括相似的浅色板材)"上表现稳定。

4.4 数据分布与验证集预测

数据集类别中心 / 框尺寸 / 中心点分布:

验证集随机一批的预测可视化:

可以观察到,验证集图中一旦出现"价签下方裸露的层板"或"端架边缘空位",模型都能用紧凑的 bbox 框住,且置信度普遍 > 0.7。


五、项目总结

做对了什么:

  1. 场景聚焦—— 不贪多,只解决"画面里所有空货位在哪"这一件事,单类 + 高召回,做到 mAP@0.5 = 93.8%;
  2. 真实数据—— 1500 张图来自真实超市场景,覆盖标准层板/端架、店内灯光/自然光/阴影、多种拍摄视角,模型泛化能力扎实;
  3. 轻量好部署—— 6 MB 的 YOLO11n 权重,单图推理 < 50 ms,巡检机器人/边缘盒/笔电都能跑;
  4. 工程化闭环—— 单图 → 批量 → 视频 → 摄像头四种入口齐备,批量页直接产出"巡店报告"形态。

还能怎么做:

  1. 接入巡检机器人—— 把当前 Demo 包成 HTTP 接口,让巡检机器人定时上传 + 触发推理,再把结果回写到补货工单系统;
  2. 多店多 SKU 关联—— 配合 OCR 识别价签 SKU,做"哪个 SKU 在哪个店哪个货架空了"的联动;
  3. 小目标增强—— 端架最上层和最下层的小空位(远距离拍摄)召回还有提升空间,可以加 Mosaic + Mixup 强化训练;
  4. 导出 ONNX/TensorRT—— 进一步压到 < 10 ms 单图,支持 1 路视频实时(25 fps)跑下来不卡。

一句话总结:用 200 行 Streamlit + 一个 6 MB 的 YOLO11n 权重,把超市"人工巡店、电话补货"的旧流程改造成"上传即看图、看图即补货"的工程化巡检台,mAP@0.5 = 93.8% 已经能直接挂到零售运营 SOP 上跑。

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

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

立即咨询