拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

YOLOv8植物叶片检测实战:从LabelMe数据转换到边缘部署避坑指南

YOLOv8植物叶片检测实战:从LabelMe数据转换到边缘部署避坑指南 简介这份资源面向农业科学、植物学研究及自动化农业管理方向的开发者与学习者提供一套基于YOLOv8的植物叶片检测完整项目帮助解决复杂背景下叶片自动识别与定位的问题适合具备一定深度学习与图像处理基础的中级读者。压缩包共5个文件约5.11MB包含Jupyter Notebook演示文件、Python脚本、Markdown说明文档及依赖清单分别用于展示检测流程与结果、实现目标追踪、说明安装与使用步骤、列出运行所需库版本。已有60人学习下载。项目围绕YOLOv8模型训练与推理展开结合OpenCV完成图像预处理、特征提取与分割等操作并借助机器学习方法学习叶片形态与颜色特征读者可据此搭建从数据标注、模型训练到结果后处理的完整检测链路理解细粒度目标检测的调优思路与工程落地方式。1. 拿到“基于YOLOv8的植物叶片检测.zip”先别急着解压这类项目真正卡住人的三个地方你从群里或者某资源站拿到一个叫“基于YOLOv8的植物叶片检测.zip”的压缩包第一反应大概率是解压、装环境、跑train.py然后发现路径全是作者机器上的绝对路径数据集里混着.DS_Store标注文件是 LabelMe 的 JSON 而不是 YOLO 的 txt。植物叶片检测这个方向本身不复杂难的是把一份别人打包好的工程变成你自己能复现、能换数据、能部署的流水线。它适合两类人一类是拿它做毕业设计或课程作业需要跑通训练和推理另一类是想把叶片病害、缺素、虫害识别落到田间摄像头或边缘盒子上需要知道模型从 640 输入到 RK3588 或 Orin 上到底要改什么。这篇不聊虚的按“数据怎么处理、环境怎么搭、训练参数怎么设、部署怎么走”的顺序把这类项目里最容易翻车的地方一条条拆开。2. 植物叶片数据集怎么从 LabelMe 标注走到 YOLOv8 能吃的格式2.1 先看清压缩包里到底有哪几类文件一个典型的“基于YOLOv8的植物叶片检测.zip”解压后目录结构通常长这样datasets/下分images和labelsimages里是.jpg或.pnglabels里可能是.txt也可能是.json。如果labels里是 JSON说明作者用 LabelMe 标完没转格式如果labels里是 txt 但每行只有类别和四个归一化坐标那才是 YOLO 格式。先别改代码用下面这条命令把文件类型和数量点清楚find datasets -type f | sed s/.*\.// | sort | uniq -c find datasets/images -type f | wc -l find datasets/labels -type f | wc -l逻辑说明第一条按扩展名统计能立刻看出标注是 JSON 还是 txt后两条对比图片和标注数量数量不一致说明有漏标或多余文件。参数上不用加-maxdepth因为这类包通常层级不深全量扫一遍更保险。如果发现 JSON 和 txt 混在一起以 JSON 为准重新转不要手动补 txt否则类别索引会对不上。2.2 LabelMe JSON 转 YOLO txt 的脚本与四个边界坑LabelMe 的 JSON 里shapes数组存的是多边形点YOLO 检测要的是矩形框所以转换时得先算多边形的外接矩形再归一化。下面这个脚本我一般直接放在项目根目录跑import json import os from pathlib import Path # 类别名到索引的映射必须和 data.yaml 里的 names 顺序一致 CLASS_MAP {leaf: 0, disease: 1, pest: 2} def convert(json_path, out_dir, img_w, img_h): with open(json_path, r, encodingutf-8) as f: data json.load(f) lines [] for shape in data[shapes]: label shape[label] if label not in CLASS_MAP: continue # 跳过未在映射表里的类别避免训练时报索引越界 points shape[points] xs [p[0] for p in points] ys [p[1] for p in points] xmin, xmax min(xs), max(xs) ymin, ymax min(ys), max(ys) # 归一化并限制在 0~1防止标注越界导致 loss 爆炸 cx max(0, min(1, (xmin xmax) / 2 / img_w)) cy max(0, min(1, (ymin ymax) / 2 / img_h)) w max(0, min(1, (xmax - xmin) / img_w)) h max(0, min(1, (ymax - ymin) / img_h)) lines.append(f{CLASS_MAP[label]} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}) out_path Path(out_dir) / (Path(json_path).stem .txt) out_path.write_text(\n.join(lines), encodingutf-8) # 调用时传入图片实际宽高不要用固定 640 convert(datasets/labels/leaf_001.json, datasets/labels_yolo, 1920, 1080)逻辑说明CLASS_MAP是转换的核心它决定了 txt 第一列的数字必须和后续data.yaml的names完全对应。归一化用图片原始宽高不是模型输入尺寸这一点很多人搞反导致框整体偏移。四个边界坑分别是多边形点顺序不固定导致外接矩形算错、标注点超出图片边界、类别名大小写不一致、JSON 里imageWidth和实际图片尺寸不符。前三个靠上面的min/max和映射表能兜住第四个需要你在转换前用 PIL 读一次真实尺寸别信 JSON 里的字段。2.3 划分训练集验证集时别用随机种子糊弄叶片数据往往同一片叶子拍了多张如果按图片随机划分同一片叶子的不同角度可能同时进训练集和验证集验证指标会虚高。常见做法是按“采集批次”或“叶片编号”分组划分。如果压缩包里没有分组信息至少按文件名前缀分比如leaf_001_*.jpg全进训练集leaf_002_*进验证集。下面这段代码演示按前缀分组import random from pathlib import Path images sorted(Path(datasets/images).glob(*.jpg)) groups {} for img in images: # 取文件名前两段作为分组键例如 leaf_001 key _.join(img.stem.split(_)[:2]) groups.setdefault(key, []).append(img) keys list(groups.keys()) random.seed(42) # 固定种子只为可复现不代表划分合理 random.shuffle(keys) split int(len(keys) * 0.8) train_keys, val_keys keys[:split], keys[split:] for phase, ks in [(train, train_keys), (val, val_keys)]: with open(fdatasets/{phase}.txt, w) as f: for k in ks: for img in groups[k]: f.write(str(img) \n)逻辑说明groups把同一片叶子的图片绑在一起random.shuffle打乱的是组而不是单张图这样验证集里不会出现训练集见过的叶片。参数0.8是训练验证比例叶片数据量少时可以调到0.7但不要再低否则验证集太小指标波动大。生成的train.txt和val.txt可以直接被 YOLOv8 的data.yaml引用。3. YOLOv8环境搭建从 Ubuntu 20.04 CPU 版到 GTX 1660 Ti 的取舍3.1 用 conda 建一个不污染系统 Python 的环境不管你是 Ubuntu 20.04 还是 Windows第一步都是隔离环境。CPU 版本和 GPU 版本的差别只在 PyTorch 安装命令Ultralytics 包本身一样。下面以 Ubuntu 20.04 为例conda create -n yolo_leaf python3.9 -y conda activate yolo_leaf # CPU 版本适合先跑通流程 pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu pip install ultralytics opencv-python labelme逻辑说明Python 3.9 是 Ultralytics 官方测试覆盖较好的版本3.10 以上偶尔会遇到opencv-python轮子不兼容。CPU 版 PyTorch 的 index-url 指向官方 CPU 轮子仓库装完体积小、依赖少适合在没独显的笔记本上先验证数据管道。如果你有 GTX 1660 Ti把第二行换成 CUDA 11.8 对应的命令即可但注意 1660 Ti 是 6GB 显存训练时batch别超过 8否则 OOM 会教你做人。3.2 验证环境是否真的能用 GPU装完别急着训练先跑三行代码确认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)逻辑说明第一行看 PyTorch 版本第二行返回True才说明 CUDA 和驱动匹配第三行打印显卡型号。如果第二行是False但你确实有 NVIDIA 显卡常见原因是驱动版本低于 CUDA 要求或者 conda 环境里装了 CPU 版 torch。这时候不要反复重装 ultralytics先nvidia-smi看驱动支持的最高 CUDA 版本再回 PyTorch 官网找对应命令。GTX 1660 Ti 在 CUDA 11.8 下跑 YOLOv8n 的 640 输入单 epoch 大约 1 到 2 分钟具体看数据集大小。3.3 data.yaml 里五个字段写错一个就白跑YOLOv8 训练靠data.yaml找数据和类别这个文件通常长这样path: /home/user/leaf_project/datasets train: train.txt val: val.txt nc: 3 names: [leaf, disease, pest]逻辑说明path是数据集根目录train和val是相对path的 txt 文件里面每行是图片绝对路径或相对路径。nc是类别数必须等于names长度多一个少一个都会在训练启动时抛索引错误。names的顺序必须和前面 LabelMe 转换时的CLASS_MAP完全一致否则模型学到的“0”可能是 disease 而不是 leaf。常见翻车是path写了 Windows 反斜杠在 Linux 下解析失败统一用正斜杠最稳。4. YOLOv8训练参数怎么设叶片检测场景下的 batch、imgsz 和学习率4.1 从预训练权重开始别从零训叶片检测数据集通常几千张从零训练收敛慢且容易过拟合。标准做法是加载yolov8n.pt或yolov8s.pt预训练权重让 backbone 复用通用特征。命令如下yolo detect train \ datadatasets/data.yaml \ modelyolov8n.pt \ epochs100 \ imgsz640 \ batch8 \ lr00.01 \ patience20 \ projectruns/leaf \ nameexp1逻辑说明modelyolov8n.pt会自动下载预训练权重n 版最轻适合 1660 Ti 和后续边缘部署如果叶片病害区分度低可以换yolov8s.pt但显存占用翻倍。imgsz640是 YOLOv8 默认输入叶片目标通常占画面比例大640 够用如果叶片在整株照片里很小提到 960 或 1280但 batch 要相应降到 4 或 2。lr00.01是初始学习率配合patience20表示 20 个 epoch 验证指标不升就早停避免无效训练。4.2 损失函数曲线怎么看才不误判训练完runs/leaf/exp1/下会有results.csv里面记录了每 epoch 的 box_loss、cls_loss、dfl_loss 和 mAP。用下面这段代码画曲线import pandas as pd import matplotlib.pyplot as plt df pd.read_csv(runs/leaf/exp1/results.csv) df.columns df.columns.str.strip() # 列名可能带空格先清理 fig, axes plt.subplots(1, 2, figsize(12, 4)) axes[0].plot(df[epoch], df[train/box_loss], labelbox_loss) axes[0].plot(df[epoch], df[train/cls_loss], labelcls_loss) axes[0].legend() axes[1].plot(df[epoch], df[metrics/mAP50(B)], labelmAP50) axes[1].legend() plt.savefig(runs/leaf/exp1/curve.png, dpi150)逻辑说明box_loss下降说明框回归在收敛cls_loss下降说明分类在学。如果box_loss震荡不降检查标注框是否有大量越界或宽高为 0。mAP50在叶片检测里通常能到 0.85 以上如果卡在 0.5 左右优先怀疑类别映射错位或验证集划分泄漏。参数上dpi150够发论文和报告不用调太高。4.3 数据增强在叶片场景下要关掉哪几个YOLOv8 默认开启 mosaic、mixup、hsv 增强。叶片检测里mosaic 把四张图拼一起可能让叶片目标变得过小如果原始数据叶片就小建议mosaic0.5或关掉。HSV 增强对颜色敏感的病害识别有帮助保留。翻转增强flipud0.5在叶片正反面区分明显时要关掉否则模型会把背面当正面。这些参数直接在训练命令后追加yolo detect train datadatasets/data.yaml modelyolov8n.pt epochs100 imgsz640 batch8 mosaic0.5 flipud0.0逻辑说明mosaic0.5表示 50% 概率做 mosaic不是完全关闭flipud0.0关闭上下翻转。改完增强后最好重新跑一次短训练epochs20看 mAP 趋势再决定是否全量训。5. 避坑与排查叶片检测项目里最常见的五条血泪记录5.1 训练启动就报 “No labels found”现象yolo detect train刚跑就退出提示找不到标签。原因data.yaml里train指向的 txt 文件路径不对或者 txt 里写的图片路径是相对路径但当前工作目录不在数据集根目录。解决把 txt 里每行改成绝对路径或者训练时cd到data.yaml所在目录再执行。用head datasets/train.txt确认路径真实存在。5.2 验证集 mAP 高得离谱推理却一塌糊涂现象验证集 mAP50 到 0.95但拿新照片推理框全乱。原因同一片叶子的不同角度被分到了训练和验证集验证集等于“见过”。解决回到 2.3 节按叶片编号或采集批次重新划分确保验证集里的叶片训练时完全没见过。这个坑在毕业设计里特别常见答辩时被问一句“验证集和训练集有没有重叠”就露馅。5.3 GTX 1660 Ti 训练到一半 OOM现象前几个 epoch 正常后面突然CUDA out of memory。原因YOLOv8 的 mosaic 增强在后期会动态调整或者batch设太大。解决把batch从 16 降到 8 或 4同时加cacheFalse避免把整个数据集缓存到显存。如果还不行imgsz从 640 降到 512但精度会掉一点。5.4 推理时类别名显示成数字现象yolo detect predict输出的框上标的是0、1不是leaf、disease。原因推理时没有加载data.yaml模型不知道类别名。解决预测命令加datadatasets/data.yaml或者用 Python API 时手动传names字典。这个不影响检测结果但影响演示效果。5.5 边缘部署时模型转换失败现象想把best.pt转到 RK3588 或 Orin转换工具报不支持的算子。原因YOLOv8 的某些 head 结构在特定工具链里没有对应实现。解决先导出 ONNX用yolo export modelbest.pt formatonnx opset12再用厂商工具转。如果还失败考虑换yolov8n而不是yolov8s小模型算子更基础。RK3588 上建议直接找厂商提供的 YOLOv8 转换示例别自己从零写。6. 把叶片检测推到边缘设备前先用 ONNX 做一次中间验证训练完拿到best.pt之后别直接往 RK3588 或 Orin 上怼。中间加一步 ONNX 导出和推理验证能提前暴露 80% 的部署问题。导出命令yolo export modelruns/leaf/exp1/weights/best.pt formatonnx opset12 simplifyTrue逻辑说明opset12是多数边缘工具链支持较好的版本simplifyTrue会调用 onnx-simplifier 去掉冗余算子。导出后用 onnxruntime 跑一张测试图import onnxruntime as ort import numpy as np import cv2 sess ort.InferenceSession(best.onnx) img cv2.imread(test_leaf.jpg) img cv2.resize(img, (640, 640)) img img[:, :, ::-1].transpose(2, 0, 1).astype(np.float32) / 255.0 img np.expand_dims(img, 0) outputs sess.run(None, {sess.get_inputs()[0].name: img}) print(outputs[0].shape) # 应为 (1, 7, 8400) 或类似逻辑说明预处理必须和训练时一致BGR 转 RGB、归一化到 0~1、HWC 转 CHW。outputs[0].shape里第二个维度是4 nc叶片三类就是 7。如果 shape 不对说明导出时类别数没带对。这一步跑通再拿 ONNX 去 RK3588 的转换工具里转 RKNN或者去 Orin 上用 TensorRT成功率会高很多。我自己的习惯是每换一个数据集先拿 20 张图跑一遍 ONNX 推理用 OpenCV 把框画出来肉眼检查。这一步花十分钟能省掉后面在板子上反复烧录的两小时。叶片检测这个方向数据质量比模型结构重要标注框贴不贴叶缘、类别分不分得清直接决定最终能不能用。希望帮到你。本文还有配套的精品资源点击获取
返回列表