尧图精选

基于YOLOv5的茶叶目标检测实战:从数据标注到树莓派部署

🕒 发布时间:2026/10/2 13:06:54 📁 来源:尧图网络
简介这份资源面向计算机视觉入门与进阶学习者以及需要落地农产品检测场景的开发者提供一套基于YOLOv5的茶叶目标检测完整项目实战方案。包内共95个文件以41个yaml配置文件、34个Python源码为主辅以5个shell脚本、4份markdown说明文档、2个txt依赖清单及Dockerfile等部署文件压缩包约242KB结构紧凑、便于快速搭建训练与推理环境。内容涵盖模型结构定义、数据增强、损失计算、指标评估、训练与检测脚本等核心模块并附带流程教程与notebook示例可帮助读者理解从数据配置、模型训练到推理部署的完整链路掌握目标检测在茶叶识别任务中的调参思路与排错方法。目前已有513人学习下载适合希望以真实项目巩固YOLOv5实践能力的中高级学习者参考。1. 茶叶目标检测到底在检什么从一片鲜叶到 YOLOv5 的落地边界茶叶目标检测说白了就是让模型在一张茶园或传送带照片里把「嫩芽」「一芽一叶」「一芽二叶」「老叶」这些目标框出来并分类。它和通用目标检测最大的区别在于目标极小、颜色高度接近、遮挡密集而且同一株茶树上不同等级嫩芽的形态差异可能只有几毫米。基于 YOLOv5 实现茶叶目标检测算法是当前性价比最高的一条路——YOLOv5 的 anchor 机制对小目标友好训练速度快部署到树莓派 5 或 Jetson 这类边缘设备也有成熟路径。这套方案适合三类人想用 YOLOv5 训练自己数据集的算法初学者、做智慧农业采摘机器人的嵌入式工程师、以及需要茶叶分级质检的产线开发者。但我要先把边界说清楚YOLOv5 不是万能的茶叶目标检测的难点不在模型结构而在数据标注一致性和小目标特征保留这两点决定了你的 mAP 能不能过 0.7。2. 数据准备与标注茶叶数据集怎么建才不白干2.1 茶叶目标检测的类别定义与采集策略茶叶目标检测翻车最多的环节不是训练而是标注。我见过太多人拿手机在茶园随手拍几百张标完训练出来 mAP 只有 0.3回头一看类别定义就错了。茶叶的检测类别必须和你的下游任务绑定如果是采摘机器人类别应该是「可采摘芽头」和「不可采摘」两类如果是分级质检类别要细到「单芽」「一芽一叶」「一芽二叶」「对夹叶」「老叶」五类。类别定义一旦确定整个数据集不能中途改改一次就得全部重标。采集时要注意三个硬指标。第一光照覆盖要全晴天顺光、晴天逆光、阴天散射光、傍晚弱光各占一定比例否则模型一到傍晚就瞎。第二拍摄距离要固定建议 30cm 到 50cm太远目标只有几个像素YOLOv5 的 P3 特征图也救不回来。第三背景要多样纯茶园背景训练出来的模型换到竹筛或传送带上直接崩。常见做法是每个类别至少 300 张有效样本五类就是 1500 张起步低于这个数别指望 mAP 好看。2.2 用 labelImg 标注茶叶并转成 YOLO 格式标注工具用 labelImg 就够了别一上来就上 CVAT学习成本不划算。安装和启动命令如下pip install labelImg labelImg启动后按w画框选类别保存为 Pascal VOC 的 XML 格式。但 YOLOv5 要的是归一化的 txt 格式每行是类别索引 x_center y_center width height全部除以图像宽高归一化到 0 到 1。转换脚本我一般自己写一个逻辑清晰可控import os import xml.etree.ElementTree as ET # 类别顺序必须和 data.yaml 里的 names 完全一致 classes [single_bud, one_bud_one_leaf, one_bud_two_leaves, mature_leaf, old_leaf] def convert(xml_dir, txt_dir, img_w, img_h): os.makedirs(txt_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() # 图像宽高优先从 XML 读读不到再用传入值兜底 size root.find(size) w int(size.find(width).text) if size is not None else img_w h int(size.find(height).text) if size is not None else img_h 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 / w y_center (ymin ymax) / 2.0 / h bw (xmax - xmin) / w bh (ymax - ymin) / h lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {bw:.6f} {bh:.6f}) with open(os.path.join(txt_dir, xml_file.replace(.xml, .txt)), w) as f: f.write(\n.join(lines)) convert(./annotations, ./labels, 640, 640)这段代码的关键参数是classes列表顺序必须和后面data.yaml的names一一对应错一位整个训练就废了。归一化用六位小数是 YOLOv5 官方推荐精度少了会有累积误差。转换完一定要抽查几张用cat看 txt 内容确认坐标都在 0 到 1 之间出现大于 1 的值说明 XML 里的宽高读错了。2.3 数据集划分与 data.yaml 配置划分比例我一般用 8:1:1训练集、验证集、测试集。茶叶数据量本来就不大验证集别低于 10%否则 mAP 波动大到没法判断模型好坏。目录结构按 YOLOv5 的约定来dataset/ images/ train/ val/ test/ labels/ train/ val/ test/然后写data.yamlpath: ./dataset train: images/train val: images/val test: images/test nc: 5 names: [single_bud, one_bud_one_leaf, one_bud_two_leaves, mature_leaf, old_leaf]nc是类别数必须和names长度一致。这里有个血泪经验path用相对路径时训练命令必须在path的上一级目录执行否则 YOLOv5 找不到图片报错信息还特别隐晦只说找不到 label其实是路径拼接错了。3. YOLOv5 环境配置与训练从 conda 到第一个权重文件3.1 conda 环境与 YOLOv5 依赖安装环境配置是新手第一道坎。我推荐 conda 建独立环境别在 base 里折腾conda create -n tea_yolo python3.8 -y conda activate tea_yolo git clone https://github.com/ultralytics/yolov5 cd yolov5 pip install -r requirements.txtPython 3.8 是 YOLOv5 兼容性最好的版本3.10 以上有些 torch 版本会出玄学问题。requirements.txt里会自动装 torch但如果你有 GPU建议先单独装对应 CUDA 版本的 torch再装其余依赖否则可能装成 CPU 版训练时torch.cuda.is_available()返回 False白等一晚上。验证环境import torch print(torch.__version__) print(torch.cuda.is_available()) print(torch.cuda.get_device_name(0) if torch.cuda.is_available() else CPU only)三行输出确认版本、CUDA 可用性、显卡型号。如果第三行是 CPU only先解决驱动和 torch 版本匹配问题别急着开训。3.2 用 YOLOv5 训练茶叶数据集的完整命令训练命令看着简单参数才是决定成败的地方python train.py \ --data ./data/tea.yaml \ --weights yolov5s.pt \ --img 640 \ --batch 16 \ --epochs 200 \ --hyp data/hyps/hyp.scratch-low.yaml \ --project runs/train \ --name tea_exp1 \ --cache逐项说。--weights yolov5s.pt用预训练权重茶叶数据量小从头训基本没戏迁移学习是标配。--img 640是输入分辨率茶叶目标小理论上 1280 更好但显存翻四倍8G 显存跑 640 是稳妥选择。--batch 16根据显存调显存不够就降到 8但 batch 太小 BN 层统计不稳mAP 会抖。--epochs 200是上限实际看早停YOLOv5 默认 patience 是 100 轮没提升就停。--hyp用 low 增强配置茶叶数据集小强增强容易过拟合到增强后的伪特征。--cache把图片缓存到内存小数据集能明显加速但数据集超过 10G 别开内存会爆。训练过程中重点看三个指标box_loss应该稳定下降如果震荡剧烈说明学习率太大mAP0.5是主指标茶叶检测能到 0.75 以上算合格precision和recall要平衡recall 太低说明漏检多采摘场景漏检比误检更致命。3.3 超参数怎么调茶叶小目标的三个必调项YOLOv5 超参数几十个茶叶检测真正要动的就三个。第一anchor尺寸。茶叶目标普遍偏小默认 anchor 是基于 COCO 的偏大。用python utils/autanchor.py --data data/tea.yaml重新聚类生成的 anchor 替换模型配置里的默认值小目标召回能涨 3 到 5 个点。第二lr0初始学习率默认 0.01茶叶数据集小我一般降到 0.005配合lrf0.1 做余弦退火训练更稳。第三mosaic增强概率默认 1.0茶叶目标密集时 mosaic 拼四张图会让目标更小更难学我一般降到 0.5后期再关掉。改超参在hyp.scratch-low.yaml里改别直接改源码。改完重新训对比 mAP 曲线一次只改一个参数否则你不知道是哪个起了作用。这是调参的基本纪律很多人一次改五个涨了不知道为啥涨跌了不知道为啥跌纯靠运气。4. 推理、部署与效果验证模型训完只是开始4.1 用 detect.py 跑通茶叶图片和视频推理训练完拿到best.pt先别急着部署用detect.py验证python detect.py \ --weights runs/train/tea_exp1/weights/best.pt \ --source ./test_images \ --img 640 \ --conf-thres 0.4 \ --iou-thres 0.45 \ --save-txt \ --project runs/detect \ --name tea_test--conf-thres 0.4是置信度阈值茶叶检测我一般设 0.4 到 0.5太低误检多太高漏检多按场景权衡。--iou-thres 0.45是 NMS 的 IoU 阈值茶叶目标密集时这个值要调低到 0.3 到 0.4否则相邻芽头会被 NMS 误删。--save-txt把检测框坐标存下来方便后续做计数或分级统计。推理结果重点看两类错误把老叶误检成嫩芽说明类别特征没学好回去检查标注密集区域漏检调低 iou-thres 或重新聚类 anchor。4.2 树莓派 5 上部署自己训练的 YOLOv5 模型边缘部署是茶叶检测真正落地的场景。树莓派 5 性能比 4 强不少但直接跑 PyTorch 版 YOLOv5 还是吃力常见做法是转 ONNX 再用 onnxruntime 推理python export.py --weights best.pt --include onnx --img 640 --opset 12导出 ONNX 后在树莓派上装onnxruntime写推理脚本。关键参数是opset 12版本太高树莓派的 onnxruntime 可能不支持。树莓派 5 上 640 分辨率单帧推理大概 200 到 400ms做实时采摘引导勉强够用要更快就降到 416 分辨率精度会掉几个点。部署时注意散热树莓派 5 满载跑推理温度能上 80 度不加风扇会降频推理时间翻倍。4.3 茶叶检测模型的验证指标与误检分析验证不能只看 mAP。茶叶检测要额外看三个指标单类 AP看哪个类别拖后腿混淆矩阵看类别之间怎么混的以及实际业务指标比如采摘场景的漏检率。跑验证python val.py \ --weights best.pt \ --data ./data/tea.yaml \ --img 640 \ --conf-thres 0.001 \ --iou-thres 0.6 \ --task test--conf-thres 0.001是验证时的低阈值为了算完整的 PR 曲线别用推理时的 0.4。--task test指定在测试集上跑别用验证集验证集参与过调参指标会虚高。跑完看runs/val下的混淆矩阵图如果one_bud_one_leaf大量被预测成one_bud_two_leaves说明这两类标注边界模糊回去统一标注标准而不是调模型。5. 避坑与排查茶叶目标检测最常见的五个翻车现场5.1 训练 loss 不降反升现象训练前几十轮box_loss和obj_loss都在涨mAP 一直是 0。原因通常是学习率太大或者标注文件格式错。先检查 labels 目录下的 txt 是不是归一化坐标有没有出现大于 1 的值。再检查data.yaml的nc和names长度是否一致。如果都正常把lr0从 0.01 降到 0.001 再试。还有一种隐蔽情况图片和 label 文件名没对上YOLOv5 找不到 label 会当成背景图训练loss 也会异常。5.2 mAP 卡在 0.5 上不去现象训练正常loss 在降但 mAP0.5 到 0.5 就平了。原因多半是 anchor 不匹配小目标。茶叶目标在 640 分辨率下可能只有 20 到 40 像素默认 anchor 最小是 10x13勉强够但聚类后的 anchor 更贴合。跑 autanchor 重新生成替换yolov5s.yaml里的 anchors 字段。另一个原因是数据量不够五类各 300 张是底线低于这个数模型学不到类间差异加数据比调参有用。5.3 推理时类别全预测成同一类现象detect.py 跑出来所有框都是single_bud。原因是data.yaml的names顺序和训练时不一致或者转换脚本里classes列表顺序变了。YOLOv5 的类别索引是硬编码的顺序错一位所有预测都错位。解决方法是训练和推理用同一份data.yaml转换脚本的classes从data.yaml读别手写两份。5.4 树莓派上推理报 onnxruntime 版本错误现象导出 ONNX 后在树莓派上加载报Unsupported model IR version。原因是导出时 opset 版本太高树莓派上装的 onnxruntime 版本旧。解决方法是导出时指定--opset 12或者升级树莓派的 onnxruntime。如果还不行用onnxsim简化模型去掉冗余算子。树莓派 5 的 ARM 架构对某些算子支持不好简化后兼容性更好。5.5 傍晚或逆光图片漏检严重现象白天图片检测正常傍晚或逆光图片大量漏检。原因是训练集光照分布不均模型没学过弱光特征。解决方法是补充弱光样本或者在推理前做直方图均衡化预处理。我一般会在推理脚本里加一步 CLAHE 增强对茶叶这种低对比度目标效果明显。但注意预处理要和训练时的增强保持一致训练没用 CLAHE推理加了反而可能掉点。6. 把茶叶检测做到产线可用一个提升小目标召回的技巧模型训完、部署跑通离产线可用还差一步小目标召回。茶叶检测最要命的是漏检一个嫩芽没检出来采摘机器人就少摘一个产线质检就漏判一个。我试过最有效的一个技巧是推理时用 TTA测试时增强简单说就是把图片翻转、缩放后分别推理再融合结果。YOLOv5 的 detect.py 自带 TTA 开关python detect.py \ --weights best.pt \ --source ./test_images \ --img 640 \ --augment \ --conf-thres 0.35 \ --iou-thres 0.4--augment就是开启 TTA会对每张图做翻转和缩放推理再 NMS 融合。代价是推理时间翻三倍左右树莓派上可能从 300ms 涨到 900ms实时场景要权衡。但在离线质检场景这个技巧能把小目标召回率提升 5 到 8 个点非常值。另一个技巧是切片推理针对超高分辨率图片。茶叶航拍图或产线高清相机图可能有 4000x3000直接缩到 640 目标只剩几个像素。做法是把大图切成 640x640 的小块每块带 20% 重叠分别推理后再把框映射回原图做 NMS。这个逻辑要自己写核心是滑动窗口加坐标还原def slice_inference(img, model, slice_size640, overlap128): h, w img.shape[:2] stride slice_size - overlap all_boxes [] for y in range(0, h, stride): for x in range(0, w, stride): # 切块边界不足时贴边补齐 x2 min(x slice_size, w) y2 min(y slice_size, h) x1 max(0, x2 - slice_size) y1 max(0, y2 - slice_size) patch img[y1:y2, x1:x2] # 推理并把框坐标加回偏移量 boxes model(patch) for box in boxes: box[0] x1 box[1] y1 box[2] x1 box[3] y1 all_boxes.append(box) # 最后对所有框做一次全局 NMS return nms(all_boxes, iou_thres0.4)slice_size和overlap是核心参数overlap 太小边缘目标会被切断太大推理次数暴增。我一般用 128 像素重叠640 的块一张 4000x3000 图大概切 35 块推理时间可接受。这个方案在茶叶航拍计数场景实测比整图缩放召回高 15 个点以上。最后说个我自己的习惯每次训完模型我都会挑 20 张最难的图——逆光、密集、遮挡——单独存一个hard_cases文件夹每次改完参数先跑这 20 张看漏检和误检有没有改善。这比看整体 mAP 敏感得多整体 mAP 涨 0.5 个点可能只是简单样本的贡献难样本才是产线真正的考验。茶叶目标检测这行模型结构不是壁垒数据和验证方法才是。希望帮到你。本文还有配套的精品资源点击获取
上一篇/下一篇内容由系统自动关联 返回资讯列表 →