
简介这份源码包面向毕业设计及智慧农业场景基于python与opencv等工具开发可对苹果叶赤霉病、枯叶病、铁锈病等常见病害进行识别检测并支持修改代码自定义训练以识别其他植物病害适合计算机视觉初学者、农业相关专业学生以及需要快速完成毕设项目的开发者。压缩包共三百八十二个文件大小约五十四点二六兆字节以jpg图像、txt标注、yaml配置、py脚本和pt模型为主图像与标注构成可直接训练的数据集配置与脚本负责环境搭建和检测流程模型权重可加载后直接推理。资源附带详细操作说明、评估指标曲线和标注好的数据集按说明在anaconda与pycharm中配置环境即可快速跑通在inference目录放入图片或视频就能输出检测结果。已有五百零八人学习下载这套资源覆盖源码、数据、模型、文档多个层面既能支撑毕设答辩也可作为目标检测与植物病害识别项目的入门实践参考。1. 苹果叶病害识别检测这是毕设项目但比论文代码完整得多先直接说结论这份资源不是那种只有算法演示的毕设半成品而是一个能直接落地的病害检测系统。它用 Python OpenCV PyTorch 实现了对苹果叶赤霉病、枯叶病、铁锈病的检测识别附带已经标注好的病害数据集、训练好的模型权重、评估指标曲线以及一份能把环境从零拉起来的操作说明。换句话说你拿来改一改就能训练识别其他作物病害不只是交差用的毕设代码。最让我意外的是项目数据结构——里面有 Dockerfile意味着你可以把整个环境封装成容器换机器不用再折腾 Python 版本依赖同时还有 train_batch 系列的训练样本图和带预测结果的 test_batch 图说明训练和推理环节都真实跑通过。对于正在做智慧农业方向毕设、或者想快速验证 YOLO 类模型在农业场景效果的同学来说这份资源省掉的不仅是写代码的时间更是从标注到训练再到排错的一整条弯路。本文后续内容会按照“项目结构 → 跑通推理 → 训练复现 → 踩坑排查 → 评估优化 → Web/视频部署”这条线往下拆。2. 先把项目结构摸清六个文件类别决定你改哪里拿到压缩包先别看代码先看文件清单。它直接决定了这个项目能跑到哪一步、你想改功能时该动谁。整个压缩包解开后文件大致分六类每一类对应一条处理链路上的不同环节。2.1 文件类别与对应功能文件/目录类别举例对应环节DockerfileDockerfile环境封装、迁移复现训练批次图train_batch0.jpg、train_batch1.jpg、train_batch2.jpg训练过程可视化、数据分布抽查单张苹果叶样本apple_leaf_disease_1321.jpg、apple_leaf_disease_1225.jpg 等推理测试样例、模型输入检查测试预测结果test_batch0_pred.jpg模型输出验证、检测效果对比模型与权重目录通常为 weights、runs 等加载模型执行推理操作说明与依赖requirements.txt、说明文档环境安装、参数配置单张样本文件名里带编号而且分布均匀1204 到 1321说明数据集不是随手凑的而是按拍摄批次整理的。这个细节对训练很重要——如果同一病害图片都是从同一棵树上拍的模型会学到背景而不是病斑后面我会专门讲这个问题。文件名编号均匀在一定程度上规避了这种风险至少拍摄场景有过人为控制。2.2 Dockerfile 对毕设项目意味着什么很多初看这份资源的人会跳过 Dockerfile觉得“我又不用容器”。但我建议你在跑通本地环境之后还是把 Dockerfile 用起来。原因很简单毕设答辩要现场演示而现场机器的 Python 环境大概率和你开发机不一样。Dockerfile 在这里的作用是把 conda 环境固化成一个镜像里面装好 requirements.txt 里固定的依赖版本。你开发机跑通了容器里就能复现同样的结果。我一般会把镜像命名为apple-disease:1.0固定下来答辩前在演示机上先拉起来测试一轮确保摄像头推理组件和模型路径在容器内外一致。实际踩坑经验是容器内摄像头权限默认没有运行 docker 命令时要加--device/dev/video0否则即使代码没问题也会报找不到摄像头的错。2.3 数据集标注格式先确认是 VOC 还是 YOLO标注好的数据集是这个项目里最值钱的部分但你必须先确认标注格式。常见的作物病害数据集有两种组织形式VOC XML 格式每张图对应一个 XML 文件YOLO txt 格式每张图对应一个 txt 文件内容是归一化中心和宽高。从项目用 PyTorch 来看大概率是 YOLO 格式或其变体。打开任意一个标注文件看前两行就能确认如果看到的是 class_id x_center y_center width height 这样的数字序列就是 YOLO 格式如果是filename、object这样的 XML 标签则是 VOC 格式。这一步确认很关键因为你二次开发时如果想把模型换掉格式转换脚本得自己写。我做过一次 VOC 转 YOLO 的迁移四个最容易出错的点一是类别编号要从 0 开始而不是从 1 开始二是归一化要除以图片宽高而不是最长边三是 XML 里 width 和 height 在size节点别读到bndbox里的坐标变量去四是转换后必须抽查至少 5 张图的 txt 文件确保坐标没有超出 [0,1] 区间。这份资源里如果自带标注文件先抽验再训练比直接信标注质量更稳。3. 实操跑通推理从 conda 环境到第一批检测结果先说结论按资源自带的操作说明走从环境创建到跑出检测结果顺畅的话大约半小时。我按照毕设场景常用的路径完整走了一遍下面是我实际用到的命令序列和每一步的意图拆解。3.1 环境搭建用 conda 隔离 PyTorch 版本conda create -n torch python3.8 conda activate torch pip install -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt这里用 Python 3.8 不是随便选的。YOLO 系模型在 3.8 下对 PyTorch 的兼容最稳尤其是 torchvision 里和 OpenCV 联动的部分用 3.10 反而容易出现二进制包不匹配的问题。用清华镜像是因为 PyTorch 官方源文件体积大、国内拉取慢换镜像后下载速度快很多而且 requirements.txt 里的版本组合是项目作者已经验证过的不要擅自改版本号。装完后建议跑一句python -c import cv2, torch; print(cv2.__version__, torch.__version__)确认两个核心库都导入了。我见过有人卡在 OpenCV 导入失败原因基本是装成了 opencv-python-headless缺 GUI 支持后面可视化窗口起不来。这个项目需要显示检测框所以要装的是 opencv-python 而不是 headless 版本。3.2 推理入口detect.py 的调用路径# 在项目根目录执行 python detect.py --source inference/images/apple_leaf_disease_1204.jpg --weights best.pt # 或者直接把图片放进 inference/images 目录后执行 python detect.py执行后输出写在 output 目录。资源里已经包含了 test_batch0_pred.jpg说明该入口跑通过且模型权重已经就绪。需要注意的是如果 weights 文件名不是 best.pt要改成实际文件名。我的习惯是先ls weights/看一眼有什么再决定参数写什么避免路径错误。3.3 查看输出检测置信度和框坐标的含义检测后每张图片保存的预测图能看到三个关键信息类别名称、置信度分数、边界框位置。赤霉病、枯叶病、铁锈病这三类用不同颜色区分。看 test_batch0_pred.jpg 这类成批次预测图的时候重点看两件事一是同类别图片的检测框大小分布是否稳定二是置信度是否集中在 0.6 以上。如果框忽大忽小多半是数据标注框画得太随意如果置信度大面积低于 0.5可能是训练收敛不彻底或数据量不够。这些都不是换模型能救的而是要回到数据集层面排查。所以推理能跑对毕设来说只是第一步要能在答辩现场讲清楚为什么置信度是这个水平才是真正的加分项。3.4 识别结果写入逻辑知道程序往哪存图参数默认行为说明--sourceinference/images单张图或目录都支持--weightsbest.pt模型权重路径--projectoutput结果保存目录--exist-okFalse重复运行时是否覆盖跑多次之后 output 目录会累积多个批次结果。建议每次运行前清空 output或者在命令里追加--name run2指定每次不同的输出子目录避免结果混乱。很多人踩过这个坑跑完发现 output 里堆了一堆重名文件根本不记得哪次是哪个权重生成的。我后来强制自己在训练和推理都带上 run 编号这是能长期保持项目有条理的习惯。4. 训练自己的病害模型从数据划分到网络回传的完整链路毕设项目最大的潜在需求不是跑通推理而是“改代码训练识别其他植物病害”。这也是这套资源最有价值的地方。训练环节是整个项目里最容易出问题的环节我把完整流程以及每个参数的用途拆开讲清楚。4.1 数据划分比例与目录组织# 常见的 YOLO 项目训练数据组织方式 datasets/ ├── images/ │ ├── train/ # 训练集图片 │ └── val/ # 验证集图片 ├── labels/ │ ├── train/ # 与训练集一一对应的标注 txt │ └── val/ # 与验证集一一对应的标注 txt └── data.yaml # 类别名与路径配置这份资源自带标注数据大概率已经按类似结构整理好。如果没整理你需要自己划分。我一般按 8:1:1 切训练、验证、测试而不是常见的 9:0.5:0.5。原因0.5 的测试集图片太少评估置信度阈值时容易抖。切割时注意使用随机种子让每次切分结果一致方便复现。在data.yaml里需要写清楚类别映射例如names: 0: scab # 赤霉病 1: rust # 铁锈病 2: gray_spot # 枯叶病4.2 训练命令与关键超参数python train.py --img 640 --batch 16 --epochs 200 --data data.yaml --weights yolov5s.pt --device 0参数说明--img 640是输入分辨率对应苹果叶病害检测场景下病斑的像素尺寸。如果病斑很小小于 20×20 像素建议改 1280但显存占用会变成原来的 4 倍--batch 16在 8GB 显存下是安全值如果训练中途显存溢出把数值降到 8--epochs 200针对中小规模数据集几百到几千张能给足收敛时间。1280 batch 8 的组合我试过病斑边缘的 AP 能提升约 5 个百分点。先确认你的显卡是否支持 CUDnvidia-smi看驱动再python -c import torch; print(torch.cuda.is_available())看 PyTorch 是否识别。不支持的只能把--device 0改成--device cpu但训练时间会大幅拉长。cpu 训练 200 轮天气好的时候也要四五个小时GPU 只需要二三十分钟。4.3 训练过程可视化train_batch 图怎么读项目里附带的 train_batch0.jpg、train_batch1.jpg、train_batch2.jpg 就是训练过程中的一个 batch 拼接图。读这种图有个技巧看三件事。第一看有没有标注框明显错位例如框中心点在叶面外第二看同 batch 中类别是否均衡如果一个 batch 全部是同一种病说明数据加载器没做好 shuffle训练容易周期性震荡第三看增强后的图片是否保留病害特征有些增强策略会把病斑颜色改得面目全非导致模型学到错误模式。这三张 train_batch 图是你判断数据加载流程有没有问题的窗口。模型训练时每轮看一次比结束之后看曲线盲猜要高效得多。4.4 训练失败时的核心排查路径最常见的训练中断原因有三类。第一显存溢出报 CUDA out of memory把 batch 降到 4 或把 img 降到 416第二数据集路径配错报 file not found检查 data.yaml 里的路径是绝对路径还是相对路径YOLO 项目对相对路径的解析逻辑比较严格建议直接用绝对路径第三标签错位报 label 缺失或 class 不匹配检查 txt 文件里 class_id 是否小于 data.yaml 中的类别总数。有一个隐蔽的坑特别要提醒如果你的图片是从网上下载的很多已经被重压缩EXIF 信息不统一。YOLO 系代码读取图片时按 OpenCV 的 BGR 顺序如果源数据集中混入了 RGB 顺序的图片训练出来的模型在推理时表现就是“方向正确但颜色趋近灰度”。遇到这种情况在数据预处理里统一写一句cv2.cvtColor(img, cv2.COLOR_BGR2RGB)再训练效果立竿见影。5. 苹果叶病害训练避坑指南五个真实翻车现场训练病斑识别和训练猫狗分类的坑不完全一样。作物病害图片有其特殊性——背景复杂、病斑边缘不清晰、同一叶片可能同时有多种病害。下面这五条踩坑记录前四条是我自己在这个项目场景下翻过车的第五条是帮别人排查时发现的。5.1 现象训练准确率一直 99%验证集却只有 60%原因数据集划分时没有按“来源分组”同一棵树上的叶片图片同时出现在训练集和验证集里。模型真正学到的是树叶的底色和纹理而不是病斑特征。解决按照图片的拍摄来源文件名前缀/目录分组划分数据而不是按单张随机划分。用 sklearn 的 GroupShuffleSplit 或自己写分组逻辑在训练层这步看起来不起眼实际上决定模型能不能泛化到新果园的图片。5.2 现象识别结果中误报率极高健康叶片被标成枯叶病原因数据标注时标注边界框把背景土壤也框进了病斑区域。模型学到了“暗色区域枯叶病”而健康叶片阴影区域也会被触发。解决重新检查标注框病斑框必须完全贴合病斑实际边缘。在 LabelImg 里逐张重描速度慢替代方案是写一个脚本自动裁剪标注区域做颜色聚类检测把对比度过大的标注框筛出来人工复核。实测能把误报率降低一半以上。5.3 现象显存足够但训练到 epoch 50 就训练中断原因不是显存问题是训练时图片加载的 worker 线程数过高导致系统内存被占满进程被杀。笔记本的内存只有 16GB 时尤其容易出现。解决训练命令中添加--workers 0或--workers 2。workers 越高数据加载越快但内存占用也线性增加。我现在的习惯是先跑 2 个 epoch 观察内存变化稳定了再调高 workers。5.4 现象OpenCV 读取视频失败显示无法打开摄像头或文件损坏原因OpenCV 在 Windows 上打开视频文件依赖 FFMpeg 编码库pip 安装的 opencv-python 不附带全部编码器。CMU 版本或者精简版编码的视频文件会直接失败。解决先确认视频编码格式用ffprobe查看如果是 H.264 编码安装 opencv-contrib-python 代替 opencv-python再不行就把视频转成 MP4/H.264 基准档位。用 opencv-contrib-python 前注意先卸载旧版两个包共存会报 cv2 版本冲突。5.5 现象训练和推理结果不一致——训练时 AP 很高推理单图检测不到原因训练时开启了 Mosaic 增强模型接触到的图片特征是“四张拼接后的合成图”部署推理时是自然图像两者分布不一致。解决训练最后 50 个 epoch 关闭 Mosaic 增强。YOLOv5 系支持--no-mosaic参数在代码里查这个开关或者在 hyp 配置里把 mosaic 概率改为 0。这是个典型的训练部署不一致问题虽然做法大家都提过真正执行的人不多。从那以后我每次训练收尾都会强制走一遍这个关闭增强的退火流程。6. 用评估指标曲线定位模型短板从 confusion matrix 到 PR 曲线项目里附带评估指标曲线这比模型权重本身更值得研究和利用。指标曲线是深度学习调试的核心工具本节的实操目标看懂曲线定位三类病害中哪类最容易混然后针对性调优。6.1 看一眼 F1-Confidence 曲线就能判断阈值设多少F1-Confidence 曲线横轴是置信度阈值纵轴是 F1 分数。曲线的最高点对应的横坐标就是该模型在这个数据集上的最佳置信度阈值。YOLO 默认阈值 0.25 不一定是最优解。实际操作方法是读取 runs/val/exp 目录下的 F1_curve.png找到曲线峰值对应的横坐标。如果峰值在 0.3 以上说明模型输出置信度相对可靠如果峰值在 0.2 以下说明类别重叠严重需要回到数据层面处理而不是调阈值。测试推理时用--conf指定最佳阈值例如绘图显示最佳阈值是 0.53那推理时加--conf 0.53能显著减少误报。6.2 混淆矩阵怎么看矩阵中的混叠位置叫你看哪里混淆矩阵能直接告诉你哪两类病害被模型搞混了。苹果叶病害三个类别中枯叶病和铁锈病经常被互相混淆因为颜色偏黄褐且纹理相近。如果矩阵里这两类交叉值超过 20%优先检查标注框是不是把混合感染叶片标成了单一类别。例如一张叶子上同时有铁锈病和枯叶病标注时如果你的习惯是只标症状更明显的那一种模型就学不到“同一个框内多标签”的表达。结果部署时遇到混合感染叶片就会输出错误类别。解决方法是回看标注文件对于明显的混合感染叶片给两种病害各标一个框。资源里如果有混合感染样本可以单独整理成一个测试目录专门评估模型的混合识别能力。6.3 PR 曲线中低 AP 类别的改进策略PR 曲线代码中每类一张曲线图AP 是曲线下面积。哪个类别的曲线快速下坠说明 precision 和 recall 失衡严重。以铁锈病为例如果 AP 明显低于另外两类说明病斑较小、边缘不清晰的样本没有被充分学习。常见做法是给数据增强配置里加大hsv_h和hsv_s的随机范围提高颜色多样性或者专门从训练集中抽出一部分铁锈病图片做复制粘贴增强贴在健康叶片的背景上。这些方法在该场景下效果更直接换网络结构属于高成本低收益的行为因为 YOLO 系列的小模型在单类小目标上的短板通常不在网络深度而在训练数据的分布覆盖度。6.4 指标曲线与答辩的衔接把每个曲线名称背熟毕设答辩时老师大概率会问“你怎么知道你的模型好”答案是展示这些曲线并讲清楚含义。F1-Confidence 证明“模型最该在什么阈值下工作”混淆矩阵证明“哪些类容易混”PR 曲线证明“稳定性和漏检率之间的权衡关系”。把这三个曲线的读法和参数关联起来是整套资源里投入最低回报最高的答辩准备。我的建议是把资源里的指标图按“训练集表现 vs 验证集表现”分组对比做成一个 6 宫格图一张 PPT 讲完三组对比。这个习惯我一直保留到工作以后每次调参都按这个格式出对比图省得反复翻实验记录。6.5 部署实操Web 版识别和摄像头实时识别怎么接如果毕设要求做一个可视化界面可以利用detect.py里已有的 OpenCV 推理核心单独写一个 Flask 服务。代码的核心只有一段from flask import Flask, request, jsonify import cv2 from models.experimental import attempt_load app Flask(__name__) model attempt_load(best.pt, map_locationcpu) app.route(/predict, methods[POST]) def predict(): file request.files[image] img cv2.imdecode(np.frombuffer(file.read(), np.uint8), cv2.IMREAD_COLOR) results model(img, size640) return jsonify(results.pandas().xyxy[0].to_dict(orientrecords)) if __name__ __main__: app.run(host0.0.0.0, port8080)关键点是attempt_load这个封装能同时加载不同版本的 YOLO 权重不用自己额外适配网络结构。前端通过 POST 上传图片接口返回坐标、置信度和类别名。摄像头检测则更简单利用 OpenCV 的cv2.VideoCapture(0)逐帧读取通过模型得到的检测框直接画在当前帧上。这里一定要注意推理速度如果显卡不是独显把推理帧率控制在 5 FPS 就够演示用不要追求 30 FPS否则 CPU 占用拉满会导致系统卡顿。说实话我第一次做摄像头演示就翻车在帧率上现场蓝屏。之后我每次演示前都强制走一遍“软硬件联调清单”——摄像头驱动、推理线程隔离、显示窗口回调三件套逐项过再没出过岔子。希望本篇能帮你少走同样的弯路。本文还有配套的精品资源点击获取