ARTICLE DETAIL

资讯详情

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

农作物病虫害图像识别毕设项目:从源码到可运行深度学习全流程

农作物病虫害图像识别毕设项目:从源码到可运行深度学习全流程 简介这份资源是2024年毕业设计级别的农作物病虫害图像识别项目Python源代码及配套说明面向计算机、人工智能、通信工程、自动化等专业的高校学生、教师与科研从业者可用于毕设、课程设计、作业或项目初期立项演示也适合具备一定基础的小白进阶学习。压缩包共373个文件约91.56MB其中18个py脚本承担数据加载、模型训练与推理等核心逻辑另有大量权重与偏置文件如conv层、fc层的weights、bn_mean、bn_variance等构成完整网络参数配合txt、md、conf、jpg及日志文件覆盖配置、说明与运行记录。目前已有169人学习下载。项目代码完整、资料齐全含设计文档经过严格测试可正常运行读者可借鉴其网络结构、训练流程与参数组织方式在此基础上修改以实现其他识别功能遇到配置与运行问题还可远程交流适合作为深度学习入门到实战的参考案例。1. 农作物病虫害图像识别项目一份毕设源码到底能跑出什么结果很多同学拿到「农作物病虫害图像识别项目python源代码及说明」这类压缩包时第一反应是解压、找main.py、直接python main.py然后被一堆ModuleNotFoundError和路径报错劝退。这个标题背后其实是一套完整的深度学习图像分类流水线数据集准备、模型选型、训练、推理、可视化界面最后打包成能写进毕设论文的成果。它解决的核心问题是——给定一张叶片照片判断它属于哪种病害比如早疫病、晚疫病、健康叶并给出置信度。适合谁适合正在做计算机毕设、需要一份能跑通、能改、能写进论文的深度学习图像识别项目的同学也适合刚入门 Python 图像识别、想找一个完整案例练手的开发者。这一章先把整条链路讲清楚后面几章再拆开动手。2. 从压缩包到可运行环境Python 依赖与目录结构怎么理拿到源码包之后最忌讳的就是在系统全局 Python 里直接装依赖。血泪经验是不同毕设项目对numpy、opencv-python、torch的版本要求经常打架全局装完别的项目就跑不起来了。所以第一步永远是隔离环境。2.1 用 conda 建一个专用环境我一般会先看压缩包里有没有requirements.txt或者environment.yml。有就照着装没有就按常见深度学习图像识别项目的依赖手动建。命令如下# 创建名为 crop_disease 的虚拟环境指定 python 3.9 conda create -n crop_disease python3.9 -y # 激活环境 conda activate crop_disease # 安装核心依赖版本按项目实际需求调整 pip install numpy opencv-python pillow matplotlib scikit-learn pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu逻辑说明conda create负责隔离避免污染全局python3.9是深度学习项目里兼容性较好的版本太新或太旧都容易在torch上翻车。opencv-python用于图像读取和预处理pillow用于格式转换matplotlib用于训练曲线可视化。torch这里给的是 CPU 版本如果你有 NVIDIA 显卡并且装了 CUDA可以把--index-url换成对应 CUDA 版本的源训练速度会快很多。参数说明-n crop_disease是环境名可以改成你自己的-y表示自动确认。--index-url指定 PyTorch 官方源国内网络环境下如果慢可以换成清华或阿里镜像但要注意镜像里不一定有全部 CUDA 版本。2.2 目录结构先看懂再动手一个规范的病虫害图像识别项目目录通常长这样crop_disease_project/ ├── data/ │ ├── train/ │ │ ├── 早疫病/ │ │ ├── 晚疫病/ │ │ └── 健康/ │ └── val/ │ ├── 早疫病/ │ ├── 晚疫病/ │ └── 健康/ ├── models/ │ └── resnet18.pth ├── utils/ │ ├── dataset.py │ └── transforms.py ├── train.py ├── predict.py ├── app.py └── requirements.txtdata/train和data/val按类别分文件夹这是torchvision.datasets.ImageFolder的标准格式类别名就是文件夹名。models放训练好的权重utils放数据加载和预处理代码train.py训练入口predict.py单张推理app.py可能是可视化界面。先确认这些文件在不在再决定从哪一步开始跑。提示如果压缩包里没有requirements.txt不要盲目pip install -r先打开看内容确认没有奇怪的包名再执行。3. 数据准备与增强病虫害图像识别的第一道分水岭模型效果好不好七成看数据。农作物病害图像有个特点类间差异小不同病害叶片长得像类内差异大同一种病在不同光照、不同角度下差别很大。所以数据准备不是简单把图片丢进文件夹就完事。3.1 数据集划分与类别平衡检查先写一段脚本统计每个类别的图片数量看看有没有严重不平衡import os from collections import Counter data_dir data/train class_counts Counter() for class_name in os.listdir(data_dir): class_path os.path.join(data_dir, class_name) if os.path.isdir(class_path): count len([f for f in os.listdir(class_path) if f.lower().endswith((.jpg, .png, .jpeg))]) class_counts[class_name] count for name, count in class_counts.items(): print(f{name}: {count} 张) # 如果最大类是最小类的 3 倍以上就需要做重采样或加权 max_count max(class_counts.values()) min_count min(class_counts.values()) print(f不平衡比例: {max_count / min_count:.2f})逻辑说明Counter统计每个类别下的图片数量os.listdir遍历文件夹。最后算一个不平衡比例超过 3 倍就要警惕。常见做法是对小类别做数据增强过采样或者在损失函数里加class_weight。参数说明data_dir指向你的训练集根目录图片后缀判断里我加了.jpeg因为很多手机拍的农作物照片是这种格式漏掉会导致统计偏少。3.2 训练集增强策略怎么配病虫害图像识别最常用的增强是随机裁剪、水平翻转、颜色抖动。颜色抖动尤其重要因为田间光照变化大。代码示例from torchvision import transforms train_transform transforms.Compose([ transforms.Resize((256, 256)), # 统一尺寸 transforms.RandomResizedCrop(224), # 随机裁剪到 224 transforms.RandomHorizontalFlip(), # 水平翻转 transforms.ColorJitter( # 颜色抖动 brightness0.2, contrast0.2, saturation0.2, hue0.05 ), transforms.RandomRotation(15), # 小角度旋转 transforms.ToTensor(), transforms.Normalize( # 归一化 mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225] ) ]) val_transform transforms.Compose([ transforms.Resize((224, 224)), transforms.ToTensor(), transforms.Normalize( mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225] ) ])逻辑说明训练集用RandomResizedCrop而不是固定Resize是为了让模型见到不同尺度的病斑ColorJitter模拟田间光照变化RandomRotation模拟拍摄角度变化。验证集只做Resize和归一化保证评估结果稳定。参数说明mean和std是 ImageNet 的统计值用预训练模型时保持一致hue0.05不要调太大否则叶片颜色失真反而影响病害特征学习。RandomRotation(15)是经验值超过 30 度可能把病斑转出画面。注意验证集千万不要加随机增强否则每次评估结果都在变你根本不知道模型有没有变好。4. 模型选型与训练ResNet18 够不够用怎么调病虫害图像识别不是 ImageNet 那种千类问题通常只有几类到几十类。用太深的网络容易过拟合用太浅的又学不到细粒度特征。ResNet18 是毕设场景下最稳的选择够轻、预训练权重好找、CPU 也能跑。4.1 迁移学习冻结与解冻的策略直接从头训练一个小数据集效果通常很差。常见做法是加载 ImageNet 预训练权重先冻结主干只训练分类头再解冻全部微调。代码import torch import torch.nn as nn from torchvision import models # 加载预训练 ResNet18 model models.resnet18(weightsmodels.ResNet18_Weights.IMAGENET1K_V1) # 替换最后的全连接层类别数改成你的病害类别数 num_classes 3 # 根据实际类别修改 model.fc nn.Linear(model.fc.in_features, num_classes) # 第一阶段冻结主干 for name, param in model.named_parameters(): if fc not in name: param.requires_grad False # 只优化分类头 optimizer torch.optim.Adam(model.fc.parameters(), lr1e-3) criterion nn.CrossEntropyLoss()逻辑说明weights...IMAGENET1K_V1加载预训练权重这是迁移学习的关键。替换fc层是因为原模型输出 1000 类你的任务只有几类。冻结主干后只训练fc可以让分类头先适应你的数据分布避免一开始就把预训练特征破坏掉。参数说明lr1e-3是分类头阶段的学习率比较大等解冻全部参数后学习率要降到1e-5到1e-4量级否则预训练权重会被冲垮。num_classes一定要和你的文件夹类别数一致不一致会在训练时报维度错误。4.2 训练循环里必须监控的三个量训练不是跑完就完事要盯着训练损失、验证损失、验证准确率。代码片段def train_one_epoch(model, loader, optimizer, criterion, device): model.train() total_loss 0 for images, labels in loader: images, labels images.to(device), labels.to(device) optimizer.zero_grad() outputs model(images) loss criterion(outputs, labels) loss.backward() optimizer.step() total_loss loss.item() return total_loss / len(loader) def evaluate(model, loader, device): model.eval() correct 0 total 0 with torch.no_grad(): for images, labels in loader: images, labels images.to(device), labels.to(device) outputs model(images) _, predicted torch.max(outputs, 1) total labels.size(0) correct (predicted labels).sum().item() return correct / total逻辑说明model.train()和model.eval()必须切换因为 BatchNorm 和 Dropout 在两种模式下行为不同。torch.no_grad()在验证时关闭梯度省显存也加速。参数说明device一般是torch.device(cuda if torch.cuda.is_available() else cpu)。如果训练损失一直降、验证损失先降后升就是过拟合要加早停或者增强。如果两个都不降先检查学习率是不是太大或者数据标签有没有错。提示训练前先跑一个 batch确认输出维度是[batch_size, num_classes]标签范围在[0, num_classes-1]能省掉很多玄学报错。5. 推理与可视化把模型变成能演示的毕设成果毕设答辩时老师不会看你训练日志他们要看的是给一张图系统能不能说出这是什么病。所以推理脚本和可视化界面是最后的脸面。5.1 单张图片推理脚本import torch from PIL import Image from torchvision import transforms def predict_image(image_path, model, class_names, device): transform transforms.Compose([ transforms.Resize((224, 224)), transforms.ToTensor(), transforms.Normalize( mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225] ) ]) image Image.open(image_path).convert(RGB) tensor transform(image).unsqueeze(0).to(device) model.eval() with torch.no_grad(): outputs model(tensor) probabilities torch.softmax(outputs, dim1) confidence, predicted torch.max(probabilities, 1) return class_names[predicted.item()], confidence.item()逻辑说明unsqueeze(0)把单张图变成 batch 维度因为模型输入要求 4 维。softmax把 logits 转成概率方便展示置信度。convert(RGB)防止灰度图或带 alpha 通道的 PNG 导致通道数不匹配。参数说明class_names的顺序必须和训练时ImageFolder的classes_一致否则预测标签会错位。这个顺序通常是按文件夹名排序建议训练完打印一次并保存下来。5.2 用 Gradio 快速搭一个演示界面如果毕设需要现场演示用 Gradio 比 PyQt 快得多几行代码就能出一个网页界面import gradio as gr def classify(img): label, conf predict_image(img, model, class_names, device) return f{label}置信度 {conf:.2%} interface gr.Interface( fnclassify, inputsgr.Image(typefilepath), outputstext, title农作物病虫害识别 ) interface.launch()逻辑说明gr.Image(typefilepath)直接给推理函数传文件路径省去手动保存上传文件。launch()会起一个本地网页答辩时浏览器打开就能演示。参数说明title可以改成你的毕设题目。如果部署在服务器上launch(server_name0.0.0.0)可以让同局域网访问但注意不要暴露到公网。6. 避坑与排查病虫害识别项目最常见的 5 个翻车点这一章是我自己踩过和帮别人排查过的问题按「现象 → 原因 → 解决」写遇到对应情况直接对号入座。6.1 训练准确率 99%验证准确率 30%现象训练集上几乎全对验证集惨不忍睹。原因数据泄漏训练集和验证集有重复图片或者验证集用了训练集的增强。解决检查两个文件夹有没有同名文件用哈希去重确认验证集 transform 里没有随机增强。6.2 预测结果永远偏向某一类现象不管输入什么图都输出同一个病害。原因类别不平衡严重模型学会了「全猜多数类」或者标签映射错了。解决先打印每个类别的样本数对少样本类做过采样再检查class_names和训练时是否一致。6.3 报错RuntimeError: Expected 4D input现象推理时报维度错误。原因单张图没有加 batch 维度。解决在transform后加.unsqueeze(0)或者用DataLoader包装。6.4 训练损失变成 NaN现象几个 epoch 后 loss 突然 NaN。原因学习率太大或者数据里有损坏图片导致异常值。解决把学习率降一个数量级写脚本遍历所有图片用Image.open().verify()检查完整性删掉坏图。6.5 换了数据集后效果暴跌现象在公开数据集上很好换成自己拍的叶片就不行。原因域偏移公开数据集背景干净自己拍的有土壤、手指、阴影。解决在训练集里加入自己拍的图片哪怕每类只有几十张增强里加RandomErasing模拟遮挡。注意排查顺序永远是「先看数据再看标签最后看模型」。大部分翻车都不是模型结构问题。7. 进阶技巧用混淆矩阵和置信度阈值把毕设做出深度如果前面都跑通了想让毕设论文多一个亮点可以加两个东西混淆矩阵和置信度阈值。混淆矩阵能告诉你模型到底把哪种病认成了哪种病置信度阈值能让系统在不确定时输出「无法判断」而不是硬猜。先画混淆矩阵from sklearn.metrics import confusion_matrix import seaborn as sns import matplotlib.pyplot as plt def plot_confusion(model, loader, class_names, device): model.eval() all_preds [] all_labels [] with torch.no_grad(): for images, labels in loader: images images.to(device) outputs model(images) _, preds torch.max(outputs, 1) all_preds.extend(preds.cpu().numpy()) all_labels.extend(labels.numpy()) cm confusion_matrix(all_labels, all_preds) sns.heatmap(cm, annotTrue, fmtd, xticklabelsclass_names, yticklabelsclass_names) plt.xlabel(预测) plt.ylabel(真实) plt.show()逻辑说明confusion_matrix的行是真实标签列是预测标签对角线越深越好。如果某两类之间互相混淆严重说明它们的特征太像可以考虑加更多这两类的样本或者换一个更强的 backbone。参数说明fmtd表示显示整数class_names顺序要和训练一致。这个图直接放进论文比只写一个准确率有说服力得多。再说置信度阈值。在predict_image里加一个判断label, conf predict_image(image_path, model, class_names, device) if conf 0.6: print(置信度不足建议人工复核) else: print(f识别结果{label}置信度{conf:.2%})0.6这个阈值不是固定的你可以用验证集画一条置信度-准确率曲线找一个准确率还不错的截断点。这样系统在遇到模糊图片时不会强行给一个错误答案答辩时老师问起来你可以说这是「带拒识的识别系统」比单纯分类多一层工程考虑。最后一个习惯每次改完代码先在一个小批量上跑通再上全量。我见过太多人改完直接跑全量等半小时报错回头找问题更痛苦。希望帮到你。本文还有配套的精品资源点击获取
返回列表