资讯动态

YOLOv8实战:厨房物品识别系统从数据标注到部署全流程

发布时间:2026/10/22 7:56:04 来源:尧图企业网站定制
大家做目标检测项目最常见的坑不是模型选型而是把 80% 的时间砸在标注和数据处理上还没砸对地方。我最近完整跑通了一个基于 YOLOv8 的多类别家庭厨房物品智能识别系统从数据采集、标注、训练、导出到部署推理写了一套可以复用的源码。这篇文章就把整个链路掰开揉碎地讲一遍包括我踩过的坑、调参的心得以及为什么在厨房这种复杂场景里 YOLOv8 依然是最稳的选择。如果你正准备做类似的特定场景识别系统或者刚入门想找个能真正落地的练手项目这篇内容可以直接当操作手册看。1. 需求分析厨房场景的识别难点与系统目标1.1 厨房物品识别到底难在哪家庭厨房不是一个干净的视觉环境。我最初把这事想简单了以为就是拿个公开数据集训一个权重完事结果在实际拍摄测试中问题一个接一个。厨房环境有几个典型特点光照变化剧烈早上阳光直射台面、傍晚只有吸顶灯、晚上还有油烟机灯混合补光物品密集堆叠调料瓶并排、碗碟摞放、刀具和砧板挨在一起同时反光材质很多不锈钢锅、陶瓷盘、玻璃瓶都会产生高光直接影响边缘特征提取。更麻烦的是很多物品外观非常接近比如玻璃碗和玻璃杯、酱油瓶和醋瓶、面粉袋和淀粉袋仅仅靠形状或者颜色根本分不开。这意味着模型不能只学轮廓还得学标签区域局部纹理体积比例这类更细粒度的线索。所以这个系统的目标不是简单识别出厨房里有个东西而是要做多类别区分并且在遮挡、光照不良、角度倾斜的情况下依然保持稳定输出。我最终把类别定在了 18 类菜刀、砧板、炒锅、汤锅、平底锅、锅铲、玻璃碗、瓷碗、浅盘、深盘、玻璃杯、马克杯、酱油瓶、醋瓶、盐罐、糖罐、洗菜盆、保鲜盒。1.2 技术选型为什么不选 Faster R-CNN 或 SSD在确定 YOLOv8 之前我其实对比过几类方案。两阶段的 Faster R-CNN 精度确实可以尤其对小目标很友好但推理速度在嵌入式设备上太难看而且部署文件繁琐。SSD 速度快但特征融合方式老旧对厨房这种小物品密集场景召回率明显不够。YOLOv8 作为单阶段检测器把这两者的优点做了不错的平衡。它用 Anchor-Free 的方式省去了 anchor 尺寸聚类的麻烦这对自定义数据集很友好不用每换一个场景就重新聚类C2f 结构加深了梯度回传路径比之前 YOLOv5 的 C3 在特征提取上更细腻损失函数采用 BCE CIoU DFL 的组合边界框回归的收敛更稳。实测同一批数据YOLOv8s 的 mAP50-95 比 YOLOv5s 高大约 3 到 5 个点而速度基本没差别。对厨房这个任务来说YOLOv8 是性价比最高的起点。2. 数据集构建与标注效果天花板的一半由这里决定2.1 自建数据集的采集策略我一开始想偷懒去网上找现成的厨房数据集找了半天发现要么是纯室内场景分类要么是商业厨房监控类别和我的需求对不上。最后决定自建核心思路就四个字模拟真实。采集时不能只对着整齐摆放的物品拍正脸那样训练出来的模型一到真实环境就废。我的采集策略是三举拍、多角度、多光照、多背景。三举是指举高俯拍、水平平拍、低角度仰拍各来一批多背景是把物品放在不锈钢台面、木质砧板、白色瓷砖、黑色岩板四种背景上分别采集多光照分为自然光、暖色吸顶灯、冷色日光灯和混合光四组。这样一轮下来每个类别收集 400 到 600 张原始图片总共大约 9000 张图像。这里有一个很关键的点图片分辨率不能太低我用手机拍摄后统一缩放到 1280x1280保留原始细节。如果原始图只有 640x640经过标注和裁剪后小物品的像素信息会损失严重尤其是酱油瓶上的小标签可能会直接糊掉。宁可多花点存储空间也不要让模型在源头就看不清。2.2 标注规范与坑位提醒标注工具我用的是 LabelImg 和 X-AnyLabeling 两种。前者轻量适合批量做矩形框后者支持 SAM 模型辅助分割对形状不规则的物品比如洗菜盆、锅铲能省不少时间。我的建议是批量粗标用 LabelImg难样本精标用 X-AnyLabeling。标注规范有几条硬性要求。第一所有类别用全大写英文命名避免中文路径和编码问题第二边界框尽可能贴边但注意不要框进背景物体第三遮挡严重的实例如果超过 30% 区域不可见直接跳过不标第四同一个物品不同姿态、不同大小都要独立标注模型才能学到尺度不变性。我在标注中吃过一次亏前 2000 张图把所有容器类都标成了一类碗结果训练出来模型看到盘子、杯子都往碗上靠mAP 直接被拉低到 0.7 以下。后来我把类别拆细重新标注同样的模型结构mAP50 从 0.71 提升到了 0.93。这件事给我最大的教训是类别的语义边界一定要在标注前定清楚最好写一个标注手册给每个类别配参考图宁可前期多花 3 天也不要后期返工 2 周。3. 环境搭建与模型训练YOLOv8 的训练流程及调参要点3.1 训练环境和数据组织训练我用的是一张 RTX 4070 12GB 显卡显存不算大但对于 YOLOv8s 是完全够用的。如果你的卡只有 6GB 甚至更低可以使用 YOLOv8n精度低一点但跑得动。建议核心依赖这样安装conda create -n yolo python3.10 -y conda activate yolo pip install ultralytics8.1.0 pip install torch2.1.1 torchvision0.16.1 --index-url https://download.pytorch.org/whl/cu118 pip install opencv-python4.9.0.80数据目录结构直接按 YOLO 官方格式来组织这个我强烈建议不要自己发明目录结构后续写代码、迁移都麻烦kitchen_dataset/ ├── images/ │ ├── train/ # 7200 张 │ └── val/ # 1800 张 ├── labels/ │ ├── train/ # 对应 txt │ └── val/ # 对应 txt ├── data.yaml # 类别定义与路径配置 └── kitchen.names # 类别名称用于后续推理显示data.yaml 的写法要注意路径最好用绝对路径因为 ultralytics 包有时不会自动拼相对路径特别是你在项目子目录里执行训练命令时。类别定义按类别名字母排好序顺序一旦定了就不要变否则权重文件和类别索引对不上推理时全错位。3.2 训练参数配置与重点说明训练其实不需要写复杂的训练脚本ultralytics 命令行就够用但参数不是随便填的。我的最终训练命令是这样的yolo detect train \ --model yolov8s.pt \ --data kitchen_dataset/data.yaml \ --imgsz 640 \ --epochs 200 \ --batch 16 \ --optimizer AdamW \ --lr0 0.001 \ --lrf 0.01 \ --warmup_epochs 3 \ --patience 20 \ --device 0 \ --project kitchen_yolov8 \ --name exp1几个关键参数值得展开说。imgsz我选 640 而不是 1280因为训练显存占用和速度更友好而 YOLOv8 本身具备一定的多尺度学习能力模型在训练中会自动随机缩放相当于隐式学习了多尺度特征。optimizer我选了 AdamW 而不是默认的 SGD实验下来在小数据集上收敛更稳前 20 个 epoch 损失就能降到一个合理区间。patience 20是早停参数如果 20 个 epoch 内验证集 mAP 没有提升就自动停止能省不少时间。lr0不要设太高0.001 是个安全的起点设 0.01 容易在前几个 epoch 把权重冲乱。训练过程中你会看到三个损失曲线box_loss、cls_loss、dfl_loss只需要关注趋势是否下降不要过度在意具体数值因为不同的标签噪声水平会造成损失基线不同。提示如果你从yolov8s.pt加载预训练权重它会自动在 COCO 的 80 类基础上做迁移学习和你的自定义类别数不一致也没关系主干特征提取层的参数会继承检测头会自动初始化。4. 工程源码结构与推理实现4.1 项目目录与模块划分训练完成后得到的best.pt只是第一步。为了能让这个系统真正用起来我整理了一套工程化的源码结构。搞工程和搞实验的区别就在这里实验只要权重文件工程还要考虑接口、可视化、批量处理、异常兜底。kitchen-detect-system/ ├── config/ │ └── class_names.py # 类别常量 ├── models/ │ ├── yolo_detector.py # 检测器封装 │ └── export_model.py # 模型导出脚本 ├── inference/ │ ├── detect_single.py # 单张图片推理 │ ├── detect_video.py # 视频流推理 │ └── detect_batch.py # 批量文件夹推理 ├── utils/ │ ├── draw_utils.py # 画框、画标签 │ ├── result_parser.py # 解析结果输出 JSON │ └── timer.py # 计时工具 ├── requirements.txt └── README.md这个结构看起来简单但每块都有讲究。class_names.py单独提炼出来是为了避免在代码中硬编码索引号检测器封装成一个类是为了让你可以在 GUI、Web API、摄像头脚本里自由调用不需要重复写模型加载逻辑。4.2 检测器核心代码与推理步骤检测器封装的核心类是YOLODetector它做三件事加载模型、预处理图像、解析预测结果。这里我贴一个精简版你可以直接改路径用# models/yolo_detector.py from ultralytics import YOLO import numpy as np class YOLODetector: def __init__(self, weights_path, conf_thres0.4, iou_thres0.45): self.model YOLO(weights_path) self.conf_thres conf_thres self.iou_thres iou_thres # 让模型固定在推理模式避免意外计算梯度 self.model.eval() def detect(self, image_bgr, verboseFalse): 输入: OpenCV BGR 图像 (numpy.ndarray) 输出: list[dict]每个 dict 为 {class_id: int, class_name: str, confidence: float, bbox: [x1, y1, x2, y2]} results self.model.predict( sourceimage_bgr, confself.conf_thres, iouself.iou_thres, verboseverbose ) boxes results[0].boxes if boxes is None or len(boxes) 0: return [] parsed [] for box in boxes: xyxy box.xyxy[0].cpu().numpy().tolist() conf float(box.conf[0]) cls_id int(box.cls[0]) parsed.append({ class_id: cls_id, class_name: self.model.names[cls_id], confidence: conf, bbox: [round(v, 2) for v in xyxy], }) return parsed写这个类有几个细节值得解释。为什么输入直接用 OpenCV 的 BGR 图而不是传一个图片路径因为实际项目里图片可能来自摄像头、来自 GUI 剪贴板、来自网络请求统一在推理层收 BGR 数组能让这个检测器适配任意输入源而不是绑定文件系统。boxes.xyxy[0]取出的坐标是 float Tensor要记得先cpu().numpy()再转 list否则在 GPU 推理时数据类型不兼容后面序列化 JSON 会报错。round(v, 2)的作用是压缩输出体积厨房物品检测对毫米级精度没有需求保留两位小数足够。4.3 两步推理流程单张检测与视频流单张图片的推理最简单核心就是调用detect()然后画框。画框这一环别忽视YOLO 原生的 plot 方法确实方便但如果你想控制字体、颜色和标签格式最好自己写一个绘制函数。我通常是这样处理的# utils/draw_utils.py import cv2 def draw_detections(image, detections, color_map): for det in detections: x1, y1, x2, y2 [int(v) for v in det[bbox]] # 定义标签文本 label f{det[class_name]} {det[confidence]:.2f} color color_map.get(det[class_name], (0, 255, 0)) cv2.rectangle(image, (x1, y1), (x2, y2), color, 2) # 解决标签在图片顶部被截断的问题 text_y y1 - 8 if y1 - 8 10 else y1 26 cv2.putText(image, label, (x1, text_y), cv2.FONT_HERSHEY_SIMPLEX, 0.55, color, 2) return image这里text_y的判断很多人会忽略。当目标框贴图片顶端时标签文本会画在画布外直接看不见。很多博客的示例代码都没有这个判断我是被坑过一次才加上的。视频流推理和单张推理的区别在于要做帧率控制。摄像头帧率通常 30fps模型单帧推理可能只要 5 到 10 毫秒GPU但你仍然不能无脑死循环读摄像头否则 CPU 占用率会拉满、风扇狂转。我的做法是加一个简单的定时器控制推理频率比如每秒最多推理 15 帧剩余时间用于画面显示和 IO# utils/timer.py import time class FPSTimer: def __init__(self, interval1.0 / 15): self.interval interval self._last 0 def wait(self): now time.time() diff self.interval - (now - self._last) if diff 0: time.sleep(diff) self._last time.time()5. 模型导出与性能优化从 PyTorch 到可部署状态5.1 ONNX 与 TensorRT 导出对比训练完成的best.pt是 PyTorch 格式依赖 torch 和 ultralytics 库没法在手机、执行效率要求高的环境里直接跑所以导出环节很关键。YOLOv8 导出 ONNX 可以一条命令完成yolo export modelkitchen_yolov8/exp1/weights/best.pt formatonnx dynamicFalse imgsz640 opset12导出时我建议dynamicFalse固定输入尺寸否则有些环境下的 onnxruntime 解析动态轴会出问题。如果你要部署到 NVIDIA Jetson 或带 TensorRT 的服务器上还可以继续转成 TensorRT engine推理速度能比 ONNX 快一倍左右yolo export modelbest.pt formatengine device0 imgsz640 halfTruehalfTrue是半精度 FP16 推理在验证深度和精度允许的损失前提下速度提升非常明显。我在 RTX 4070 上实测FP16 推理大约比 FP32 快 40%而厨房物品检测这个任务并不要求像素级的精确定位FP16 完全够用。5.2 推理速度与精度实测我对自己这套系统做了一次完整的基准测试测试样本 800 张验证集图片结果如下表模型规格推理耗时(ms/帧)mAP50mAP50-95显存占用(MB)YOLOv8n2.10.870.631170YOLOv8s4.30.930.712190YOLOv8s TensorRT FP162.60.920.701480从表里能清楚看出来YOLOv8s 的 mAP50 是 0.93已经可以保证绝大多数厨房场景下的正确识别。如果你追求极限速度YOLOv8n ONNX Runtime在普通 CPU 上也能跑到 40ms 以内作为入门级部署方案也是可选的。实际项目中我更推荐YOLOv8s TensorRT FP16因为精度和速度的平衡点最好显存占用也压得住。6. 常见问题排查与实战心得6.1 训练阶段最容易翻车的地方训练时最常遇到的坑之一是损失刚开始下降过了 30 个 epoch 后验证集 mAP 反而掉下来。这个通常是两个原因一是学习率没有配合余弦退火策略后期还在大步长更新参数把已收敛的权重顶出了最优点二是数据增强过强比如 mosaic 概率设到 1.0到了训练后期模型仍然在接收大量高难度合成图始终学不到稳定特征。我的做法是早期开启 mosaic 增强让模型快速学习全局特征到训练后 30 个 epoch 手动把 mosaic 概率降为 0.5甚至关闭让模型在真实分布上精修。YOLOv8 的增强策略可以通过在训练前临时改配置文件或者手动设置参数实现官方默认值不全适合自定义小数据集。还有一个容易被忽略的细节类别不均衡。我当时白糖罐的图片只有 180 张而炒锅图片有 600 张模型天然更倾向于预测炒锅造成白糖罐检测的召回率只有 0.7。解决手段是给低样本类别增加一个权重系数。YOLOv8 没有直接在命令里暴露类别权重参数但可以通过数据增强——对少量类别做更多地复制粘贴增强或者在损失函数层面修改权重实现。我采用了后一种方式直接修改损失计算中的类别权重向量把白糖罐通道权重调到 2.5训练后召回率提升到了 0.86。6.2 推理阶段的问题速查表症状可能原因解决方案检测框总是偏小一圈训练时标注框过紧标注时留 2~3 像素边距或推理后按比例外扩 5%推理结果反复闪烁视频帧抖动导致检测不稳定对相邻帧检测框做平滑处理取前 5 帧的加权平均玻璃材质检测漏检高光反光导致特征丢失数据增强中加入高斯噪声、亮度扰动模拟反光场景某类别完全没有预测框类别索引和 names 顺序错位检查 data.yaml 与推理端 class_names.py 顺序是否一致CPU 推理极慢模型在 CPU 上用 FP32 直推导出 ONNX 后使用 onnxruntime或换 smaller 模型规格6.3 我做这个项目最后悔的一件事如果让我重新做一遍我会在第一天就建立完整的失败样本归档机制。现在项目跑起来之后每天都能收集到新场景下识别失败的图比如红酒开瓶器、空气炸锅配件、小熊形状的隔热手套这些在训练集里完全没见过。我一开始懒得管直到系统在展示 demo 时连续几次把隔热手套识别成抹布我才意识到持续标注 增量训练才是这类长尾场景系统的真正护城河。所以如果你要复刻这个项目建议在整个流程中至少留出 30% 的时间做数据闭环部署一套带记录功能的推理程序每 1000 帧自动截取置信度低于 0.3 的检测结果每周人工难例再标注补充进训练集进行增量训练。这套机制跑起来之后系统的实用性会明显甩开那些一次性训练完就结束的 demo。写完这些还是要强调一句YOLOv8 这种成熟框架最怕的不是用错而是不做场景适配。厨房物品识别这种特定领域项目真正有价值的部分永远在数据处理和工程封装这两层模型只是把前期工作的价值兑现出来而已。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑