ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

基于YOLOv5与树莓派的智能冰箱食材检测系统实践

基于YOLOv5与树莓派的智能冰箱食材检测系统实践 1. 项目概述当冰箱学会“看”东西你有没有过这样的经历打开冰箱看着里面塞得满满当当的食材却完全想不起来那包绿叶菜是什么时候买的那盒酸奶是不是已经过期了或者那块肉还能不能吃。然后为了保险起见你可能会把一些看起来“可疑”的食物直接扔掉造成了不小的浪费。又或者你心血来潮想做一道菜却不确定冰箱里是否还有关键的配料必须把所有东西都翻出来确认一遍。“Fridge_Aliments_Detector”冰箱食材检测器这个项目就是为了解决这些痛点而生的。它的核心目标很简单让冰箱“看见”并“认识”里面的每一样东西。通过摄像头和人工智能技术自动识别冰箱内的食材种类、数量甚至估算其新鲜度并将这些信息数字化、可视化。这听起来像是未来智能家居的一个场景但实际上随着开源硬件和计算机视觉技术的普及我们自己动手实现一个基础版本已经不再是遥不可及的事情。这个项目非常适合对物联网、嵌入式开发、计算机视觉特别是目标检测感兴趣的开发者或者任何希望将AI技术应用于解决实际生活问题的爱好者。它融合了硬件选型、软件部署、模型训练和前后端交互等多个环节是一个综合性极强的练手项目。通过构建它你不仅能深入理解YOLO、SSD这类目标检测模型如何在资源受限的设备上运行还能掌握如何设计一个完整的、从感知到应用的数据流。接下来我将以一个实践者的角度带你从零开始拆解这个项目分享我在搭建过程中遇到的坑、做出的权衡以及最终让冰箱“睁开眼”的全过程。2. 项目整体设计与核心思路拆解在动手写第一行代码或连接第一根线之前我们必须把整个系统的蓝图规划清楚。一个典型的“Fridge_Aliments_Detector”可以拆解为以下几个核心模块其工作流如下图所示概念示意[摄像头] -- [图像捕捉] -- [边缘计算设备] -- [AI模型推理] -- [结果解析] -- [数据存储/展示] | | | V [物理冰箱] ------------------------------------------------------ [用户终端]2.1 核心需求与方案选型背后的逻辑这个项目的需求看似单一——识别冰箱里的东西但细究起来挑战不少环境复杂冰箱内部光照不均开门亮关门暗物品摆放杂乱、重叠还有反光的包装袋和玻璃瓶。物品多样食材种类繁多形态各异从规则的盒装牛奶到不规则的西兰花都需要识别。实时性与功耗我们不可能让冰箱门一直开着进行识别理想的触发时机是开门瞬间。这就要求系统能快速唤醒、完成识别并进入低功耗休眠。同时设备长期在低温、潮湿环境中运行稳定性要求高。成本与精度平衡使用顶级服务器和大型模型固然精度高但成本、功耗都不现实。必须在有限的资源下找到最佳平衡点。基于这些挑战我的方案选型思路如下硬件平台边缘计算单元树莓派Raspberry Pi是首选。原因有四社区生态极其丰富遇到问题几乎都能找到答案性能足够运行轻量级AI模型GPIO引脚方便连接传感器如门磁开关功耗相对较低。我选用的是Raspberry Pi 4B 4GB版本它的CPU和内存对于本项目绰绰有余。如果追求更低功耗和成本Pi Zero 2 W也可以考虑但推理速度会慢一些。摄像头模块为了适应冰箱内部可能的光线不足我选择了Raspberry Pi High Quality Camera并搭配一个广角镜头如6mm。广角能覆盖更大的视野减少识别盲区。更重要的是这款摄像头支持更换镜头并且感光性能优于普通的Pi Camera Module。务必选择支持在弱光下仍有较好表现的型号。AI模型这是核心中的核心。考虑到边缘设备的算力大型模型如Faster R-CNN直接出局。我在YOLOv5s和MobileNet-SSD之间做了权衡。YOLOv5s速度快精度高社区活跃预训练模型多且PyTorch生态友好。它的“一次检测”特性非常适合实时场景。MobileNet-SSD模型更小在CPU上推理可能更快但精度通常稍逊于同级别的YOLO。我最终选择了YOLOv5s。因为对于冰箱这个相对固定的场景我们可以通过针对性的数据集训练来大幅提升精度而YOLOv5s在Pi 4B上经过优化如使用PyTorch的TorchScript或ONNX Runtime后完全能达到“开门-识别-关门”这个时间窗口内的实时性要求目标在1-2秒内完成单次识别。触发机制最简单可靠的是使用干簧管门磁传感器。当冰箱门打开磁铁远离电路断开产生一个信号给树莓派的GPIO从而触发拍照和识别程序。这比定时拍摄或运动检测更节能、更准确。数据存储与展示识别结果物品标签、数量、时间戳可以存储在树莓派本地的SQLite数据库中。为了远程查看我使用Flask搭建了一个轻量级Web服务器提供简单的API和网页界面。你也可以将数据同步到云端如Home Assistant实现更智能的联动比如过期提醒、食谱推荐。注意供电与放置。树莓派和摄像头需要稳定的5V供电。可以考虑从冰箱外部引线或者使用大容量充电宝需注意低温对电池的影响。设备应放置在冰箱内壁顶部或灯罩附近避免冷凝水直接滴落并确保摄像头视野无遮挡。2.2 系统架构与数据流设计确定了核心组件后整个系统的软件架构可以这样设计触发层一个Python脚本使用RPi.GPIO库持续监听GPIO引脚状态。门磁传感器信号变化从高到低即触发中断。采集层触发后脚本调用picamera2库新版树莓派推荐或opencv捕获一张高分辨率照片。为了应对光照变化可以考虑在拍照前短暂点亮一个补光灯通过另一个GPIO控制或者使用自动白平衡和曝光。推理层捕获的图像被送入预处理流程缩放至模型输入尺寸如640x640并归一化。然后加载事先转换并优化好的YOLOv5s模型TorchScript格式进行推理。这一步是性能瓶颈需要重点优化。解析与后处理层模型输出边界框、置信度和类别。我们需要应用非极大值抑制NMS去除重复框并根据置信度阈值如0.5过滤掉不可靠的检测结果。最后将识别出的物品名称和数量进行统计。存储与展示层将统计结果例如{“apple”: 3, “milk”: 1, “yogurt”: 2}连同时间戳和原始图片路径可选写入SQLite数据库。Flask服务定时从数据库读取最新结果通过一个简单的网页展示“当前冰箱存货清单”。还可以增加一个历史记录页面查看物品消耗趋势。这个架构清晰地将硬件交互、AI推理和软件服务解耦便于后续的调试和功能扩展。3. 核心环节实现与实操要点3.1 数据集准备与模型训练教AI认识你的冰箱这是项目成败的关键。用公开数据集如COCO训练的通用模型在冰箱这个特殊场景下表现会非常差。你必须训练一个专属的“冰箱食材模型”。1. 数据采集工具直接用你的树莓派摄像头拍。这是最真实的数据。在不同时间、不同摆放方式单独、重叠、在袋子/盒子里、不同冰箱隔层拍摄几百到上千张图片。确保覆盖开门和关门内部灯亮/灭两种状态。技巧同类物品的不同品牌、不同包装也要拍比如“利乐包牛奶”和“玻璃瓶牛奶”。对于易混淆的物品如青椒 vs. 彩椒需要更多样本来区分。2. 数据标注工具推荐使用LabelImg或更现代的CVAT、Roboflow。它们可以生成YOLO格式的标注文件.txt每行包含类别id x_center y_center width height坐标是归一化后的。规范框要紧贴物体边缘。被遮挡严重的物体可以不标或者只标可见部分。定义清晰的类别。是标“蔬菜”还是细分到“西红柿”、“黄瓜”初期建议从20-30种你冰箱里最常见的食材开始细分类别效果更好。例如apple,banana,egg,milk_carton,yogurt_cup,lettuce。3. 模型训练与优化环境在性能更强的电脑有GPU最佳上训练而不是树莓派。使用YOLOv5官方仓库。关键步骤# 克隆YOLOv5 git clone https://github.com/ultralytics/yolov5 cd yolov5 pip install -r requirements.txt # 按照YOLOv5要求的目录结构放置你的数据集 # yolov5/data/ # ├── images/ # │ ├── train/ # │ └── val/ # └── labels/ # ├── train/ # └── val/ # 创建 dataset.yaml 配置文件dataset.yaml示例# dataset.yaml path: ../datasets/fridge # 数据集根目录 train: images/train val: images/val # 类别列表 names: 0: apple 1: banana 2: milk_carton # ... 你的其他类别开始训练python train.py --img 640 --batch 16 --epochs 100 --data ./data/dataset.yaml --cfg ./models/yolov5s.yaml --weights yolov5s.pt --name fridge_detector--img 640: 输入图像尺寸。更小如320速度更快精度可能下降。--batch 16: 批大小根据你的GPU内存调整。--epochs 100: 训练轮数观察损失曲线防止过拟合。--weights yolov5s.pt: 加载预训练权重进行迁移学习这是提升小数据集性能的关键。4. 模型导出与优化训练完成后得到best.pt权重文件。需要将其转换为适合树莓派部署的格式。bash # 导出为 TorchScript 格式 python export.py --weights runs/train/fridge_detector/weights/best.pt --include torchscript --img 640得到的best.torchscript.pt文件就是可以在树莓派上加载的模型。你还可以尝试导出为ONNX格式并用ONNX Runtime进行推理有时速度更快。实操心得数据集的“脏活”决定模型上限。标注质量比数据量更重要。一个常见的坑是类别不平衡比如“鸡蛋”的图片远多于“牛排”模型会对“鸡蛋”更敏感。解决方法一是收集更多少数类别的数据二是在训练时使用类别权重。另外训练后期如果验证集精度不再上升可以尝试加入一些“困难样本”模型识别错的图片进行针对性训练。3.2 边缘端部署与推理优化将训练好的模型部署到树莓派上并实现高效推理是另一个挑战。1. 树莓派环境配置bash # 更新系统 sudo apt update sudo apt upgrade -y# 安装Python3及pip通常已预装 # 安装必要库 pip install torch torchvision --extra-index-url https://download.pytorch.org/whl/cpu pip install opencv-python-headless picamera2 numpy flask sqlite3 注意PyTorch的ARM版本可能安装较慢也可以考虑使用提前编译好的wheel文件。2. 推理脚本核心代码剖析python import torch import cv2 from picamera2 import Picamera2 import time import sqlite3 from datetime import datetime# 1. 加载模型 (确保路径正确) model torch.jit.load(best.torchscript.pt, map_locationcpu) model.eval() # 设置为评估模式 # 2. 定义类别名称列表 (必须与训练时一致) class_names [apple, banana, milk_carton, ...] # 3. 图像预处理函数 def preprocess(image, img_size640): # 将图像从BGR转换为RGB image cv2.cvtColor(image, cv2.COLOR_BGR2RGB) # 调整大小并保持长宽比进行填充 # ... (具体填充逻辑略) # 归一化 [0,255] - [0,1] image image / 255.0 # 转换维度: HWC - CHW并增加批次维度 image image.transpose(2, 0, 1) image torch.from_numpy(image).float().unsqueeze(0) return image # 4. 主循环监听GPIO触发 # 这里简化实际使用RPi.GPIO def detect_on_trigger(): picam2 Picamera2() # 配置摄像头参数如分辨率、帧率 config picam2.create_still_configuration(main{size: (1920, 1080)}) picam2.configure(config) picam2.start() while True: # 等待门磁传感器触发例如GPIO引脚下降沿 # if door_open(): time.sleep(0.1) # 模拟等待 print(Door opened! Capturing image...) # 捕获图片 image picam2.capture_array() # 获取numpy数组 # 预处理 input_tensor preprocess(image) # 推理 with torch.no_grad(): predictions model(input_tensor)[0] # YOLOv5输出 # 5. 后处理解析预测结果 # 应用置信度阈值和NMS conf_threshold 0.5 iou_threshold 0.45 # ... (使用torchvision.ops.nms或自定义实现) detections [] # 存储最终检测框 for pred in filtered_predictions: x1, y1, x2, y2, conf, cls_id pred label class_names[int(cls_id)] detections.append({label: label, confidence: conf, bbox: [x1, y1, x2, y2]}) # 6. 统计并存储结果 inventory {} for det in detections: label det[label] inventory[label] inventory.get(label, 0) 1 print(fCurrent Inventory: {inventory}) save_to_db(inventory) picam2.stop() def save_to_db(inv_dict): conn sqlite3.connect(fridge_inventory.db) c conn.cursor() # 创建表如果不存在 c.execute(CREATE TABLE IF NOT EXISTS records (timestamp TEXT, item TEXT, count INTEGER)) ts datetime.now().isoformat() for item, count in inv_dict.items(): c.execute(INSERT INTO records VALUES (?, ?, ?), (ts, item, count)) conn.commit() conn.close() 3. 性能优化技巧模型量化将模型权重从FP32转换为INT8可以显著减少模型大小并提升推理速度精度损失通常很小。PyTorch提供了动态量化和静态量化工具。使用LibTorchPyTorch的C前端。相比Python用C加载TorchScript模型进行推理速度会有明显提升。这对于追求极速响应的场景是终极方案但开发复杂度更高。图像尺寸推理时输入的图像尺寸直接影响速度。在可接受的精度损失下尝试将img_size从640降到416甚至320。预热在程序启动后先使用一张虚拟图片进行一次推理触发模型加载和初始化避免第一次真实检测时耗时过长。注意事项树莓派的内存与交换空间。YOLO模型和OpenCV处理图像会比较耗内存。确保树莓派有足够的交换空间swap否则可能在推理时因内存不足而崩溃。可以通过sudo dphys-swapfile swapoff和sudo dphys-swapfile swapon临时调整或编辑/etc/dphys-swapfile永久修改CONF_SWAPSIZE。3.3 Web服务与数据可视化让数据变得可读、可用项目才算完整。一个简单的Flask应用足以胜任。# app.py from flask import Flask, render_template, jsonify import sqlite3 from datetime import datetime, timedelta app Flask(__name__) def get_latest_inventory(): conn sqlite3.connect(fridge_inventory.db) c conn.cursor() # 获取最新一次记录的时间戳 c.execute(SELECT MAX(timestamp) FROM records) latest_ts c.fetchone()[0] if not latest_ts: return {} # 获取该时间戳下的所有物品 c.execute(SELECT item, count FROM records WHERE timestamp ?, (latest_ts,)) rows c.fetchall() conn.close() return {item: count for item, count in rows} app.route(/) def index(): inventory get_latest_inventory() # 可以在这里添加一些简单的逻辑比如高亮显示快过期的物品需要额外数据 return render_template(index.html, inventoryinventory) app.route(/api/inventory) def api_inventory(): inventory get_latest_inventory() return jsonify(inventory) app.route(/history) def history(): conn sqlite3.connect(fridge_inventory.db) c conn.cursor() # 获取过去7天的记录按天聚合 # ... (具体SQL查询略) history_data c.fetchall() conn.close() return render_template(history.html, historyhistory_data) if __name__ __main__: app.run(host0.0.0.0, port5000, debugFalse) # 生产环境关掉debug对应的templates/index.html可以非常简单!DOCTYPE html html headtitleMy Fridge Inventory/title/head body h1Current Fridge Contents/h1 pLast updated: {{ last_update_time }}/p !-- 需要从数据库传递时间 -- ul {% for item, count in inventory.items() %} li{{ item }}: {{ count }}/li {% endfor %} /ul /body /html现在只要树莓派和你的手机/电脑在同一个局域网你就可以通过http://树莓派IP:5000来查看冰箱里有什么了。4. 常见问题、调试技巧与未来扩展在实际搭建过程中你几乎一定会遇到下面这些问题。这里是我踩过坑后总结的排查清单。4.1 模型识别不准或漏检这是最常见的问题九成原因出在数据上。症状某些物品永远识别不出来或者经常误识别为其他东西。排查与解决检查训练数据打开验证集图片用训练好的模型跑一遍看哪些图片识别错了。把这些“困难样本”加入到训练集中重新标注和训练。调整置信度阈值推理时的conf_threshold可能设得太高如0.7导致很多不确定的预测被过滤掉了。尝试逐步调低如0.3、0.4观察召回率是否提升同时注意误检是否会增多。类别不平衡如果“苹果”有100张图“牛排”只有10张模型自然会偏向“苹果”。解决方案是收集更多“牛排”的图片或者在训练时使用--weights参数为不同类别设置不同的损失权重YOLOv5支持。环境差异训练数据都是在白天灯光下拍的但实际识别是在晚上冰箱灯下进行。确保训练数据覆盖了所有可能的光照和场景。4.2 树莓派推理速度太慢症状从触发到出结果要5-10秒冰箱门都快关上了。排查与解决检查输入尺寸确认推理脚本中的img_size是否与模型导出时一致且是否过大。尝试改为320。使用量化模型这是提升速度最有效的方法之一。研究PyTorch的量化工具将模型转换为INT8。关闭不必要的进程树莓派上可能运行了其他服务。用htop命令查看CPU和内存占用关掉不用的。考虑硬件加速树莓派有GPUVideoCore VI和NPU某些型号但用PyTorch直接调用比较麻烦。可以研究TensorFlow Lite或ONNX Runtime对树莓派硬件的支持它们有时能更好地利用硬件加速。不过这会涉及模型格式的再次转换。4.3 摄像头相关问题症状图片模糊、过暗、过曝或者角度不对拍不全。排查与解决对焦手动调整摄像头镜头对焦环确保冰箱内大部分区域清晰。曝光与白平衡在picamera2配置中可以手动设置曝光时间ExposureTime和模拟增益AnalogueGain避免在开门瞬间灯光变化导致画面全白或全黑。可以尝试固定这些参数而不是用自动模式。补光如果冰箱内灯光太暗可以考虑在摄像头旁边加一个小型LED补光灯由GPIO控制在拍照瞬间点亮。注意灯光角度避免直射镜头产生光晕。广角畸变广角镜头边缘物体会变形可能影响识别。可以在训练数据中就包含边缘位置的物体让模型学习这种畸变或者在图像预处理时进行畸变校正。4.4 项目扩展思路基础功能实现后这个项目还有巨大的想象空间新鲜度与存量估算新鲜度对于水果蔬菜可以通过颜色、纹理变化来粗略估计。这需要更复杂的模型如图像分类或分割模型并收集同一物品在不同腐败阶段的图片进行训练。存量估算对于牛奶、果汁等液体可以通过识别包装盒并估算其剩余高度需固定摄像头和物品位置。对于鸡蛋可以直接数边界框。对于散装物品估算难度较大。语音交互与购物清单集成语音助手如对接HomePod、小爱同学可以问“冰箱里还有牛奶吗”或者自动将快消耗完的物品加入购物清单。能耗与使用习惯分析记录每次开门的时间和时长分析家庭使用冰箱的习惯甚至与智能插座联动在非高峰时段进行节能管理。多摄像头与3D重建在冰箱的每一层都安装摄像头通过多视角图像进行简单的3D重建更精确地定位物品和估算体积。我个人在实际操作中的体会是这个项目的乐趣和挑战各占一半。乐趣在于看着冰冷的硬件和抽象的代码最终组合成一个能解决实际生活问题的智能系统那种成就感无与伦比。挑战则在于从实验室环境到真实物理世界的“最后一公里”异常坎坷光线、角度、物品的随意摆放每一个变量都可能让精心训练的模型“翻车”。因此最重要的经验是拥抱迭代。不要指望第一个版本就完美。先从识别5种你最常放的、形状规则的东西开始比如可乐罐、牛奶盒、鸡蛋让整个流程跑通。然后再一种一种地增加新品类同时不断用新收集的“问题图片”去反哺训练集。这个过程本身就是机器学习项目落地的标准缩影——一个持续优化、永无止境的循环。
返回列表