
简介基于YOLOv8的水果叶片病害图像分割设计面向毕业设计、课程设计与机器学习实践者聚焦作物叶片斑点、黄斑、褐斑等病害的自动识别与分割。压缩包共25个文件包含19张标注示例图像、4个Python脚本、1个Markdown说明和1个Word文档总大小3.02MB结构简洁便于查阅。已有27人学习浏览。脚本覆盖训练、验证、预测及界面交互等环节配套图像样例与说明文档可支撑从数据预览、模型训练到病害分割结果输出的完整流程。该资源既适合快速理解YOLOv8目标检测与分割任务的代码组织方式也可作为农业病害诊断项目的起点便于进一步优化模型精度并适配自定义数据集对深度学习应用开发有直接参考价值。1. 一个 .zip 里装着整套 YOLOv8 叶片病害分割方案先搞清楚它到底要解决什么水果叶片病害识别这类项目检测模型只能给你一个矩形框告诉你“这片叶子有病”但病斑到底占多大面积、扩散到什么程度框是答不上来的。基于 YOLOv8 的叶片病害图像分割本质是把病斑区域逐像素地“抠”出来每一片病斑对应一个 mask面积、形状、位置一起拿到。这个能力直接服务于病情分级和精准施药比单纯目标检测更贴近农业现场的需求。这个压缩包标题之所以常见于毕业设计和工程验证是因为它把“图像分割算法选型→数据集标注→训练调参→指标评估→导出部署”整条链路都压进了一个课题里适合正在做相关方向的学生也适合想快速验证分割方案可行性的工程师照着落地。2. 把叶片病害数据变成 YOLOv8 能吃的格式标注、转换与目录组织2.1 标注工具怎么选LabelMe 是默认答案做图像分割训练第一道坎是标注。YOLOv8-seg 官方数据格式要求每个目标由一组归一化多边形顶点表示而 LabelMe 导出的 JSON 正好是“多边形 类别名”的结构两者配合非常顺。备选工具还有 X-AnyLabeling 和 CVAT但 LabelMe 的优势在于单机离线可用、安装简单、标注结果直观项目里常见做法就是它。标注时把病斑边缘用多边形逐点描出来类别按病害类型命名比如 apple_scab、apple_rust、leaf_blight 这类英文标识。这里要特别注意同一张图上重叠的病斑也要逐一分 mask 标注漏标会导致训练时模型把重叠区域当成背景分割结果会莫名缺角。标注完的 JSON 文件与图像同名存放在一起等下转换脚本要按这个约定读取。标注质量直接决定分割上限模型只是把标注的规律学出来。叶片边缘模糊、病斑边界不清晰的图宁可多花时间放大描边也不要草草框个大概。用 LabelMe 自带的分割预览功能每标完一张就从“标签列表”里核对一遍类别和形状能省下后期不少返工时间。2.2 labelme 转 YOLOv8 分割格式转换脚本与归一化细节LabelMe 的 JSON 里shapes数组的每个元素是“label points”而 YOLO 分割格式的每一行是“类别ID 归一化后的顶点坐标序列”。转换脚本的核心就两件事把类别名映射成数字ID把像素坐标除以图像宽高归一化到 0~1。import json import os from pathlib import Path def labelme_to_yolo_seg(json_path, out_dir, class_dict): json_path: LabelMe 导出的 JSON 文件路径 out_dir: 输出的 YOLO 分割标签目录 class_dict: 类别名 - ID 的映射例如 {apple_scab: 0, apple_rust: 1} with open(json_path, r, encodingutf-8) as f: label json.load(f) img_w label[imageWidth] img_h label[imageHeight] txt_name Path(json_path).stem .txt lines [] for shape in label[shapes]: cls_name shape[label] if cls_name not in class_dict: # 未在类别表里的标注直接跳过避免脏数据进训练 print(f跳过未知类别: {cls_name} in {json_path}) continue cls_id class_dict[cls_name] norm_points [] for x, y in shape[points]: # 坐标归一化x 除以图宽y 除以图高 norm_points.append(f{x / img_w:.6f}) norm_points.append(f{y / img_h:.6f}) lines.append(f{cls_id} .join(norm_points)) if lines: out_path Path(out_dir) / txt_name with open(out_path, w, encodingutf-8) as f: f.write(\n.join(lines)) else: # 标注文件为空时也生成空 txt与 images 目录一一对应 Path(out_dir / txt_name).touch()这段脚本有几个点容易翻车。归一化时x / img_w和y / img_h必须分别用宽和高不要图省事统一除以宽否则叶片会被横向拉伸mask 形状完全变形。imageWidth和imageHeight必须与 PGN/JPG 实际尺寸一致批量处理时可以用 PIL 二次确认。逐点坐标保留 6 位小数足够太多小数反而让标签文件膨胀。此外每个 JSON 转换前要确认图像没有在标注后被裁剪过否则坐标会和图像内容错位。2.3 数据集目录组织与类别平衡检查YOLOv8-seg 训练时默认按固定目录结构读取数据fruits_leaf_seg/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ └── data.yaml标签文件与图片同名后缀 .txt放在对应的 labels 目录下。划分比例常见做法是 8:1:1 或 9:1而且要按“整张图像”划分不能把同一张图切出的 patch 散到多个集合里否则验证集会泄漏训练信息mAP 虚高。data.yaml 是训练入口内容如下# data.yaml path: ./fruits_leaf_seg # 数据集根目录相对或绝对路径都行 train: images/train val: images/val test: images/test nc: 2 # 类别数 names: [apple_scab, apple_rust] # 类别名必须与 class_dict 一致常见错误是nc与names长度不一致训练直接报错另一个是训练数据里某个类别只有十几张分割 mask 学不充分表现为验证集上该类 AP 很低。建议训练前统计每个类别的实例数量最少的类别不要低于总量的 5%不够就用数据增强或者补标数据。统计脚本很简单遍历 labels 目录统计每个类别 ID 出现次数即可这里不展开。3. 训练配置从最小跑通到损失曲线解读3.1 环境搭建CPU 也能跑但要认清时长预期热词里高频出现的“ubuntu20.04 搭建 yolov8 环境 cpu 版本”说明很大一部分人只有 CPU 环境。YOLOv8-seg 用 CPU 训练小型数据集是可行的只是要有耐心。GTX 1660 Ti 这类 6GB 显存显卡能跑yolov8s-seg纯 CPU 则建议用yolov8n-seg起步。# 创建虚拟环境并安装 ultralytics python3 -m venv yolov8_env source yolov8_env/bin/activate pip install ultralytics只要这一步装完不报错环境就算通了。GPU 用户再加一句pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118按你本机 CUDA 版本选择NVIDIA 驱动版本老的话就装 cu118。CPU 用户装默认的 CPU 版 torch 即可不用额外指定。验证环境是否正常一条命令跑通推理yolo predict modelyolov8n-seg.pt sourcehttps://ultralytics.com/images/bus.jpg第一次运行会下载预训练权重能看到分割 mask 叠加在原图上就算成功。如果这一步卡在“下载超时”手动从官方仓库下载yolov8n-seg.pt放到当前目录再运行常见做法是把权重文件放到项目根目录的weights文件夹里命令改成model./weights/yolov8n-seg.pt。3.2 训练参数epochs、batch、imgsz、patience 的推荐设定训练自己的数据集用 yolov8n-seg 起步命令如下yolo segment train \ modelyolov8n-seg.pt \ datafruits_leaf_seg/data.yaml \ epochs100 \ imgsz640 \ batch8 \ patience30 \ device0 \ workers4 \ seed42modelyolov8n-seg.pt是官方预训练权重它会自动加载 COCO 上学到的特征再在叶片数据集上微调收敛速度和精度都远好于从零训练。imgsz640是默认值如果叶片图像里病斑很小比如只有几十个像素建议升到 1024但显存占用会翻倍还多CPU 训练时间也会显著拉长。batch在 GPU 上建议从 8 起步显存不够就降到 4CPU 上 batch8 往往已经能让内存吃紧。patience30是早停参数连续 30 轮验证集 mAP 不涨就停止训练省时间。对新手来说最实用的做法是把epochs100配合patience30一般到 60 轮左右就能看到效果。seed42固定随机种子保证复现时结果一致这个参数经常被忽略但写论文或做对比实验时必须固定。类别不均衡时可在命令里加class_weightsTrueYOLOv8 会对样本少的类别加大 loss 权重。另一种做法是调fraction0.8快速验证数据没问题再全量训练。3.3 训练日志与损失曲线看什么才算正常训练时终端会滚动输出每一轮的box_loss、seg_loss、cls_loss、dfl_loss和验证集指标。热词里的“yolov8 画损失函数曲线图”其实就是从runs/segment/train/目录下的results.png直接看的训练结束后 Ultralytics 会自动画出 loss 和 mAP 曲线。正常收敛的表现是前 20 轮 loss 快速下降之后进入平缓期验证集mAP50稳步上升到后期趋于平稳。如果seg_loss降不下去先检查 mask 标注是否粗糙如果cls_loss高大概率是类别 ID 错位如果训练集 loss 一直降但验证集 mAP 不涨是过拟合调大patience提前止损或者增加数据增强。训练结束后runs/segment/train/weights/下会有best.pt和last.pt以后验证推理都用best.pt。这一步是整条链路的分水岭很多人训练完不看曲线直接跑下一个实验结果反复在同一个问题上翻车损失曲线图是最直接的排查工具。4. 验证评估与模型导出mAP、mask 可视化与 ONNX 部署4.1 验证集指标怎么读mAP50、mAP50-95 与 mask 精度训练完先对验证集跑一次评估yolo segment val \ modelruns/segment/train/weights/best.pt \ datafruits_leaf_seg/data.yaml输出里最重要的两个指标是mAP50和mAP50-95。mAP50是 IoU 阈值 0.5 时的平均精度要求低新模型一般能到 0.8 以上mAP50-95是 0.5 到 0.95 每隔 0.05 取平均要求高得多叶片病害这类小目标通常 0.5~0.7 就算不错。如果mAP50-95明显偏低不一定是模型问题可能是标注边界不平滑、框太小也不排除类别不均衡。除了数字还要看runs/segment/val/下保存的可视化图片。它会把预测的 mask 画在原图上绿框代表正确、红框代表漏检或误检。这里你很快会发现问题某些病斑被分割成两半、mask 边缘锯齿严重、或者把叶脉误判为病斑。这些现象在指标上很难看出来但肉眼看可视化一眼就能定位。4.2 导出 ONNX跨平台推理的关键一步训练完的.pt只能在 PyTorch 环境跑实际部署时需要导出成 ONNX 或 TensorRT。RK3588、Hi3516CV610 这类边缘设备上的部署热词里讨论很多导出命令如下yolo export \ modelruns/segment/train/weights/best.pt \ formatonnx \ imgsz640 \ opset12导出后得到best.onnx可以用 ONNX Runtime 加载。这里常踩的坑是导出时imgsz必须与训练时一致否则换尺寸后 mask 输出分辨率会变化推理精度下降。另外 ONNX 的输出是四个张量检测框、类别、置信度、mask 系数mask 系数要配合原型 mask 做后处理这跟直接在 PyTorch 里拿结果不一样。用 ONNX Runtime 做简单推理import onnxruntime as ort import numpy as np from PIL import Image # 加载 ONNX 模型 sess ort.InferenceSession(best.onnx) input_name sess.get_inputs()[0].name # 预处理resize 归一化注意要与训练时的 imgsz 保持一致 img Image.open(leaf.jpg).resize((640, 640)) img_array np.array(img).astype(np.float32) / 255.0 img_array img_array[:, :, ::-1] # RGB - BGR img_array np.transpose(img_array, (2, 0, 1))[None, ...] # HWC - NCHW outputs sess.run(None, {input_name: img_array})ort.InferenceSession加载模型后输入是归一化到 0~1 的 BGR 图像NCHW排布。不同版本 Ultralytics 导出的输出张量顺序略有差异建议用sess.get_outputs()打印每个输出的 shape再对照官方文档确定哪一个是 mask 系数。这一步属于“黑匣子”区域很多人卡在输出张量解读上最好的办法是先用 Python 完整跑一遍yolo segment predict与 onnx 输出的数值对比逐项对齐。4.3 部署到边缘设备前的权重压缩CPU 机器上跑分割推理n 模型本身就比较快但边缘设备内存有限时仍建议做 INT8 量化。ONNX Runtime 提供quantize接口常见做法是准备一小批校准图片量化后用同样指标再验证一次掉点超过 2% 就换回 FP16 或者原模型。量化不是这篇文章能穷尽的但记住一点INT8 对 mask 边界的影响比检测框更明显量化后务必看一眼可视化输出。5. 常见问题避坑从标注错位到训练中断的实战排查5.1 现象训练 loss 下降很快但验证集上 mask 全部偏到叶片边缘第一次跑就碰到这问题loss 还挺好看但 mask 全部画在叶片边缘、病斑区域一片空白。原因标注 JSON 里的坐标没有归一化或归一化时用错了参考尺寸。LabelMe 的 JSON 里imageWidth是原始图宽但很多人用预处理后的裁剪尺寸除以坐标导致 mask 整体偏移。解决检查转换脚本中img_w与img_h来源必须与原始图像尺寸一致转换后随机抽三张图把 txt 坐标反向画到图上人工比对这一步能拦下 90% 的错位问题。5.2 现象训练时报 “Assertionncdoes not match” 直接中断训练开始前检查data.yaml时报错提示类别数不匹配。原因data.yaml的nc写成了 3但标签里实际只有 2 类或者names列表比nc少一个。解决先统计数据集里所有出现过的标签 ID再倒推nc。用python -c遍历 labels 目录统计即可或者直接让代码在转换阶段打印class_dict全集。还有一个常见变体是标注里出现空文件无目标YOLOv8 会跳过它但要确保空 txt 存在不要缺失文件列表里的对应项。5.3 现象CPU 训练时内存暴涨跑到第 20 轮被 OOM 杀掉CPU 上跑 yolov8m-seg 或以上规格batch 设 16训练到中途内存耗尽直接被杀。原因CPU 训练时每个进程都持有数据加载缓存workers与batch双高导致内存占用爆炸用 GPU 训练时显存限制掩盖了这个问题。解决CPU 上把workers降到 2batch降到 4如果还涨加一行cacheFalse关掉数据缓存宁可在数据读取上慢一点也不让训练中途翻车。另外 CPU 训练的预期是yolov8n-seg每轮 3~5 分钟起步别拿 m 模型硬撑。5.4 现象训练中断后再启动直接从第 0 轮开始训练跑到一半停电或手动 CtrlC重新执行同样的命令发现又从 0 开始。原因Ultralytics 的resume机制需要显式开启默认不自动加载断点。解决中断前训练目录里的last.pt就是后悔药重新运行yolo segment train resume modelruns/segment/train/weights/last.pt它会自动读取上次训练的状态和参数从断点继续。关键点是中断后不要修改data.yaml路径否则恢复流程会找不到数据集。5.5 现象小病斑总是漏检大叶片上多个小点只检出一个分割结果里大块病斑都能圈出来但小病斑漏检很多可视化图上全是红框。原因imgsz640时图像里小于 10×10 像素的病斑在特征图上只剩一两个像素分割头学不到足够的特征。解决把imgsz升到 1024同时给训练命令加augmentTrue让 Ultralytics 自动做随机裁剪增强如果还是不够按 512 的滑窗把大图切块训练推理时再用滑窗拼接。另一个偏方是换用yolov8m-seg或yolov8l-seg但小目标问题更多由输入尺寸决定不是简单的模型越大越好。6. 让分割结果真正可用mask 面积统计与置信度筛选的落地技巧训练完成的模型只是第一步给植保用户看时他们真正关心的是“病斑面积占叶片面积多少”。YOLOv8 的 mask 输出是二值矩阵计算面积占比可以用几行 Python 完成import cv2 import numpy as np # results 是 yolo predict 的输出 for r in results: for mask in r.masks.data.cpu().numpy(): # mask 是 0/1 的二值矩阵sum 即像素面积 disease_area (mask 0).sum() leaf_area mask.shape[0] * mask.shape[1] ratio_percent disease_area / leaf_area * 100 print(f病斑面积占比: {ratio_percent:.2f}%)实际使用中要注意多张病斑 mask 叠在同一片叶子上时这个比值会大于 100%需要先做一次并集合并再计算。置信度阈值conf0.25是默认值生产环境中建议调高到 0.4宁可漏掉边界模糊的病斑也不要让误检干扰病情统计。在这类项目上我自己的教训是拿到训练结果后永远先看三张可视化图再谈指标指标是模型在平均意义上的表现可视化才能暴露病斑边界、小目标漏检这类具体问题。模型导出 ONNX 之前用验证集先确认 mask 输出比部署后才发现问题少了整轮返工。这个方向技术上已经成熟YOLOv8-seg 的分割能力配合合理的标注质量完全能支撑农业病害识别场景的落地试验希望这条链路能帮你在自己的数据集上少走几步弯路。本文还有配套的精品资源点击获取