
简介这份资源面向计算机视觉入门者、课程设计或毕业设计开发者提供一套基于YOLOv5的果蔬识别完整方案覆盖数据集、训练代码与使用教程帮助读者快速搭建可运行的果蔬分类与检测系统。压缩包共56个文件约94.07MB包含14个Python脚本、12个PNG与9个JPG等图像素材、6个TXT说明、4个XML标注文件、2个H5权重模型及readme文档涵盖数据读取、数据划分、模型训练、实时摄像头识别与界面交互等模块。数据集覆盖土豆、圣女果、大白菜、大葱、梨、胡萝卜、芒果、苹果、西红柿、韭菜、香蕉、黄瓜等常见果蔬类别并附带CNN与MobileNet两种训练过程记录、结果图与热力图便于对比模型表现。已有3770人学习下载适合希望掌握目标检测流程、复用权重与界面代码、快速完成果蔬识别项目的读者参考。1. 果蔬识别为什么总在“最后一公里”翻车从 yolov5 数据集到能跑通的系统做过果蔬分拣、智能秤、无人零售柜的人都有一个共同体会模型在实验室里 mAP 能到 0.9搬到现场就认不出被塑料袋半遮的苹果或者把青椒和黄瓜混成一类。问题往往不在网络结构而在数据集和工程链路。yolov5 果蔬识别数据集系统代码教程这套东西本质上是把“数据采集—标注—训练—推理—部署”这条链路打包成一个可复现的最小闭环让你不用从零攒数据、不用猜超参数、不用自己写推理服务。它适合三类人想入门目标检测但被数据集卡住的学生、要给分拣线加视觉能力的嵌入式工程师、以及需要快速验证果蔬识别可行性的产品团队。这一章先把这套系统到底解决什么问题讲清楚后面几章再拆数据集结构、训练参数、代码落地和踩坑记录。2. 拆开果蔬数据集目录结构、类别设计和标注规范2.1 果蔬数据集和通用检测数据集的差别在哪通用目标检测数据集比如 COCO、VOC类别动辄几十上百单类样本几千张标注框大而清晰。果蔬数据集完全是另一个物种类别集中在苹果、香蕉、橙子、番茄、黄瓜、青椒、土豆、胡萝卜这些日常品类但同一类的外观差异极大——苹果有红富士、青苹果、黄元帅番茄有粉果、红果、串收番茄。更麻烦的是遮挡和堆叠一筐橙子互相压着标注框重叠率很高模型很容易学成“看到橙色就框一大片”。果蔬识别数据集通常按 YOLO 格式组织每张图对应一个同名 txt每行是class x_center y_center width height坐标归一化到 0 到 1。类别文件classes.txt或data.yaml里的names列表决定类别顺序这个顺序一旦定下就不能乱改否则训练时标签全错位。我一般会把类别按“外形差异大、不易混”的原则排序比如把颜色相近的番茄和苹果隔开减少类别索引写错时的排查成本。提示果蔬类别命名建议用英文小写加下划线比如green_pepper、red_apple避免中文路径在部分训练脚本和部署环境里出现编码问题。2.2 从原始图片到 YOLO 标签标注和转换的实操步骤拿到一批果蔬图片后第一步是筛选。模糊、过曝、严重遮挡的图直接删别心疼这些图进训练集只会拉低精度。第二步用 labelImg 或 CVAT 标注导出 YOLO 格式。如果手里是 VOC 的 xml需要转成 YOLO 的 txt转换脚本如下import xml.etree.ElementTree as ET import os # 类别列表顺序必须和 data.yaml 里的 names 一致 classes [apple, banana, orange, tomato, cucumber, green_pepper] def convert_voc_to_yolo(xml_path, out_txt_path, img_w, img_h): tree ET.parse(xml_path) root tree.getroot() lines [] for obj in root.iter(object): cls_name obj.find(name).text if cls_name not in classes: continue # 跳过未定义类别避免索引越界 cls_id classes.index(cls_name) 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) # 归一化并转成中心点加宽高 x_center (xmin xmax) / 2.0 / img_w y_center (ymin ymax) / 2.0 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) with open(out_txt_path, w) as f: f.write(\n.join(lines))这段代码的关键点有三个类别列表顺序必须和训练配置一致归一化用的是图片真实宽高不是标注工具里显示的缩放尺寸坐标保留六位小数足够再多没必要。转换完随机抽十张图用可视化脚本画框检查确认框的位置和类别都对再进入训练。2.3 数据集划分和 data.yaml 的写法果蔬数据集一般按 8:1:1 划分训练、验证、测试。划分时要注意同一批次、同一背景的图片不能同时出现在训练和验证集里否则验证精度虚高。常见做法是按采集批次划分比如上午拍的进训练下午拍的进验证。data.yaml的写法如下path: ./fruits_dataset train: images/train val: images/val test: images/test nc: 6 names: [apple, banana, orange, tomato, cucumber, green_pepper]nc是类别数必须和names长度一致。path用相对路径时训练脚本的工作目录要对否则会报找不到图片。我习惯在训练前跑一句python -c import yaml; print(yaml.safe_load(open(data.yaml)))确认配置能正常解析这个习惯帮我省过好几次“路径写错但报错信息看不懂”的时间。3. 用 yolov5 训练果蔬模型超参数怎么设、训练怎么盯3.1 果蔬场景下的模型选型和超参数起点yolov5 有 n、s、m、l、x 五个规格。果蔬识别如果部署在树莓派 4B 或 RK3568 这类边缘设备上直接选 yolov5n 或 yolov5s输入尺寸 640 起步。别一上来就用 yolov5x参数量大、推理慢边缘设备根本跑不动。如果服务器端推理yolov5m 是精度和速度比较平衡的选择。超参数方面果蔬数据集通常几千到几万张epochs设 100 到 300batch-size根据显存调8G 显存跑 yolov5s 加 640 输入batch 设 16 比较稳。img-size如果果蔬在图中占比小比如传送带上远距离拍摄可以提到 960但推理耗时也会涨。学习率用默认的lr00.01配合余弦退火如果训练 loss 震荡厉害降到 0.001 再试。hyp配置文件里mosaic增强默认开启对果蔬堆叠场景有帮助但如果你的图里果蔬都是单个摆放mosaic 可能引入不真实的拼接可以关掉观察对比。3.2 启动训练和关键日志怎么看训练命令如下python train.py \ --data data.yaml \ --weights yolov5s.pt \ --img 640 \ --batch 16 \ --epochs 200 \ --device 0 \ --project runs/train \ --name fruits_exp1--weights用预训练权重果蔬数据集样本量不大时从头训练很难收敛预训练权重能明显加快。--device 0指定第一块 GPUCPU 训练把--device换成cpu但速度会慢很多。训练开始后重点盯三个指标box_loss、obj_loss、cls_loss。box_loss不降说明框回归有问题检查标注框是否准确obj_loss高说明模型分不清前景背景可能是负样本太少或图片里果蔬太小cls_loss高说明类别混淆比如番茄和苹果分不开需要增加难例或检查类别标签。验证集上的mAP0.5是主要参考但别只看这一个数。如果mAP0.5高而mAP0.5:0.95低说明框的位置不够准实际分拣时可能抓偏。我一般要求mAP0.5到 0.85 以上mAP0.5:0.95到 0.6 以上再考虑部署。3.3 训练完的模型怎么验证和导出训练结束后runs/train/fruits_exp1/weights/下会有best.pt和last.pt。用best.pt在测试集上跑一遍python val.py \ --data data.yaml \ --weights runs/train/fruits_exp1/weights/best.pt \ --img 640 \ --task test--task test会输出测试集上的精度指标。如果测试集精度比验证集低很多说明数据划分有问题或者过拟合需要检查划分逻辑和增强策略。导出 ONNX 用于部署python export.py \ --weights runs/train/fruits_exp1/weights/best.pt \ --include onnx \ --img 640 \ --batch 1--batch 1导出的是单张推理的模型边缘设备部署常用。如果要用 TensorRT把--include换成engine但需要在有 TensorRT 环境的机器上导出。导出后务必用onnxruntime跑一张图对比 PyTorch 和 ONNX 的输出差异差异过大说明导出有问题。4. 推理代码和部署从单张图片到视频流4.1 单张图片推理的最小代码训练完模型下一步是写推理代码。yolov5 仓库自带detect.py但实际项目里往往需要把推理逻辑嵌到自己的服务里。下面是一个最小推理示例import torch import cv2 import numpy as np # 加载模型map_location 保证在 CPU 上也能加载 GPU 训练的权重 model torch.hub.load(ultralytics/yolov5, custom, pathruns/train/fruits_exp1/weights/best.pt, map_locationcpu) model.conf 0.4 # 置信度阈值果蔬分拣建议 0.4 到 0.5 model.iou 0.45 # NMS 的 IoU 阈值堆叠场景可适当调低 img cv2.imread(test_fruit.jpg) results model(img) results.print() # 打印检测到的类别和坐标 results.save(output/) # 保存带框的图片conf设太低会误检把背景里的圆形物体当成苹果设太高会漏检尤其是被遮挡的果蔬。iou在果蔬堆叠场景下调到 0.4 左右能减少重叠框被误删的情况。results.pandas().xyxy[0]可以直接拿到检测结果的 DataFrame方便后续接分拣逻辑。4.2 视频流推理和帧率控制视频流推理和单张图片的区别在于要控制帧率不能每帧都跑模型否则 CPU 或 GPU 吃满。常见做法是隔帧推理或者用队列做异步。下面是一个简单的视频流推理框架import cv2 import torch model torch.hub.load(ultralytics/yolov5, custom, pathbest.pt, map_locationcpu) model.conf 0.45 cap cv2.VideoCapture(0) # 摄像头或视频文件路径 frame_count 0 while cap.isOpened(): ret, frame cap.read() if not ret: break frame_count 1 if frame_count % 3 ! 0: continue # 每三帧推理一次降低负载 results model(frame) annotated np.squeeze(results.render()) cv2.imshow(fruit_detect, annotated) if cv2.waitKey(1) 0xFF ord(q): break cap.release() cv2.destroyAllWindows()frame_count % 3是隔帧推理的简单实现实际项目里可以根据推理耗时动态调整。如果部署在树莓派 4B 上yolov5s 加 640 输入单帧推理大概 200 到 400 毫秒隔三帧跑一次勉强能到 5 到 8 FPS够用但不流畅。要更流畅就换 yolov5n 或者降输入尺寸到 416。4.3 部署到边缘设备的注意事项边缘设备部署果蔬识别模型绕不开量化。yolov5 支持导出 ONNX 后用 ONNX Runtime 或 TensorRT 推理。RK3568 这类芯片有 NPU需要把 ONNX 转成 RKNN 格式转换时注意输入尺寸和归一化参数要和训练时一致。树莓派 4B 没有 NPU只能用 CPU 推理建议用 yolov5n 加 416 输入配合 ONNX Runtime 的量化版本速度能提升一倍左右。注意量化后的模型精度通常会掉 1 到 3 个点果蔬识别里如果类别颜色相近量化后混淆会更明显。量化前先用验证集跑一遍原始模型量化后再跑一遍对比每个类别的精度变化掉得厉害的类别考虑保留浮点模型或增加该类样本。5. 果蔬识别避坑记录五条血泪经验5.1 现象训练 loss 正常下降但验证 mAP 一直是 0原因data.yaml里的names顺序和标注时的类别索引不一致或者nc写错。YOLO 训练时不会报错但标签全错位模型学不到东西。解决训练前用脚本抽查十张图的标签把 txt 里的类别索引映射回类别名和图片里的实际物体对比。确认无误再开训。5.2 现象模型在验证集上精度很高实际部署时频繁误检背景原因验证集和训练集来自同一批次、同一背景模型学到了背景特征而不是果蔬特征。这是果蔬数据集最常见的翻车点。解决按采集批次划分数据集验证集用不同时间、不同光照、不同背景的图片。如果条件允许验证集里加入一些没有果蔬的负样本图片让模型学会区分前景和背景。5.3 现象推理时检测框位置偏移抓取总是偏几厘米原因训练时的输入尺寸和推理时的输入尺寸不一致或者导出 ONNX 时没有指定正确的--img参数。YOLO 对输入尺寸敏感尺寸不匹配会导致框回归出错。解决训练、验证、导出、推理四个环节的输入尺寸保持一致。导出 ONNX 时显式指定--img 640推理时把图片 resize 到 640 再送入模型。5.4 现象堆叠果蔬只检测出最上面一层下面的全漏了原因NMS 的 IoU 阈值设得太高重叠框被误删或者训练集里堆叠样本太少模型没学会处理遮挡。解决推理时把iou降到 0.4 甚至 0.35保留更多重叠框。训练集里补充堆叠场景的图片标注时把被遮挡但可见面积超过 30% 的果蔬也标上。5.5 现象模型在开发机上跑得好部署到边缘设备后精度暴跌原因边缘设备推理框架的预处理和后处理与训练时不一致比如归一化方式不同、颜色通道顺序不同BGR 和 RGB 搞反、量化精度损失。解决部署前用同一张测试图在开发机和边缘设备上分别跑一遍对比检测结果。预处理阶段确认归一化参数是0-1还是0-255颜色通道是 RGB 还是 BGR。量化模型先用验证集评估精度损失可接受再上线。6. 把果蔬识别精度再提一档难例挖掘和类别平衡的实操技巧训练完第一版模型后别急着部署先做一轮难例挖掘。具体做法是用best.pt在训练集上跑推理把置信度在 0.3 到 0.6 之间的检测结果导出来人工复核。这些是模型“犹豫”的样本往往集中在遮挡、小目标、颜色相近的类别上。把这些图挑出来重新标注或补充标注加入训练集再训一轮精度通常能涨 2 到 5 个点。类别不平衡是果蔬数据集的另一个隐形杀手。苹果、香蕉这类常见品类样本多杨桃、火龙果这类小众品类样本少模型会偏向多数类。解决办法有两个一是过采样少数类把少数类图片复制多份但要注意别复制完全相同的图配合随机裁剪、颜色抖动做增强二是在损失函数里给少数类加权yolov5 的hyp配置里可以调cls_pw参数但效果不如直接补样本明显。下面是一个难例挖掘的筛选脚本把低置信度检测结果对应的图片路径导出来import torch import os import glob model torch.hub.load(ultralytics/yolov5, custom, pathbest.pt, map_locationcpu) model.conf 0.3 # 放宽阈值捞更多候选 img_dir fruits_dataset/images/train hard_cases [] for img_path in glob.glob(os.path.join(img_dir, *.jpg)): results model(img_path) df results.pandas().xyxy[0] if len(df) 0: continue # 置信度在 0.3 到 0.6 之间的算难例 uncertain df[(df[confidence] 0.3) (df[confidence] 0.6)] if len(uncertain) 0: hard_cases.append(img_path) with open(hard_cases.txt, w) as f: f.write(\n.join(hard_cases)) print(f共找到 {len(hard_cases)} 张难例图片)这个脚本把置信度在 0.3 到 0.6 之间的检测结果对应的图片路径写进hard_cases.txt人工复核这些图确认是漏标还是模型确实分不清。漏标的补标分不清的考虑增加该类样本或调整类别定义。我一般每轮训练后跑一次难例挖掘迭代两到三轮模型在测试集上的表现会明显更稳。还有一个容易被忽略的点果蔬识别系统的输入图片质量。现场摄像头如果有油污、水雾或者光照不均匀再好的模型也白搭。部署前先解决成像问题镜头定期清洁补光灯角度调好这些工程细节比调模型参数更影响最终效果。我自己踩过的坑是花了两周调模型最后发现是摄像头镜头脏了擦干净后精度直接涨了十个点。希望帮到你。本文还有配套的精品资源点击获取