
简介这份基于YOLOv8的农田智能虫情测报灯害虫种类识别系统面向计算机视觉、深度学习方向的在校学生与毕业设计开发者提供从模型训练到可视化界面的完整闭环。项目代码均已测试运行成功内置yolov8n与best等预训练权重配套完整数据集可一键训练并生成核心指标曲线图、混淆矩阵、F1分数曲线、精确率-召回率曲线、验证集预测结果及标签分布图满足毕设答辩和课程设计演示需求。压缩包共8个文件包含3个Python源文件模型训练、视频检测、可视化界面、3个PyTorch权重文件及2个说明文档整体仅15.91MB轻量易部署。目前已有65人学习下载适合计科、人工智能、自动化等专业学生拿来即用若基础较好也可在现有架构上二次开发扩展更多虫情识别功能。注意仅限学习参考勿作商业用途。1. 先说清楚这套虫情识别系统在做一件什么事先说结论这套基于YOLOv8的害虫种类识别方案最值得抄的不是那个训练好的权重而是它的数据采集链路和“拍照—识别—计数”的整体节奏。 农田虫情测报灯在夜间用诱虫光源把趋光性害虫引到撞击屏附近虫子掉落到拍照区后相机拍下照片系统再对照片里的目标做检测和分类输出“这是什么虫、大概多少只”。标题里的YOLOv8只是其中一个环节真正决定上线后好不好用的是数据集是否贴近灯下真实成像、部署教程是否能覆盖现场这台相机和边缘设备。这套方案适合两类人一类是拿它做课设或毕设需要同时交代模型、界面和数据集另一类是给植保公司做产品原型想用一套低成本的“灯下拍摄 边端推理”把人工计数替换掉。你不用把识别精度做到和实验室论文一样吓人只要把“常见害虫有哪些、大概量级多大、现场耐不耐用”三件事说清楚就已经能支撑一次答辩或一次现场小规模试点。2. 从虫情测报灯到标注数据集硬件链路、采集策略与YOLO格式落地2.1 测报灯工作链路先有拍照节拍再有识别测报灯不是一直拍照也不是每拍一张都交给模型跑通常按照一个固定节拍工作夜间定时亮起诱虫光源昆虫扑灯后被撞击屏挡落掉进下方的接虫盘或拍照白板。相机安装在接虫盘正上方使用红外对射或定时器触发每隔一段时间拍一张之后补光灯闪一下保证成像亮度一致。这个硬件链路决定了后续所有算法策略。模型看到的图不是自然景色的虫而是“白底 均匀补光 固定俯视视角”的虫。对识别来说这反而是好事背景干扰少特征相对稳定。但如果相机曝光、白平衡或补光强度在部署后被改动模型精度会明显下降这个问题我后面会在避坑章节展开。常见做法是让拍照板做成浅色磨砂面避免镜面反光相机尽量选定焦手动锁定曝光和焦距不要让镜头在每次拍照时自动对焦。自动对焦在夜间灯诱场景会来回拉风箱拍出来的图时模糊时清晰大量废图不但干扰识别还影响数据集标注质量。2.2 采集三类样本灯下现场拍、公开数据集补充、难例单独挑很多人在数据集上偷懒直接下载几百张公开害虫图片就开始标结果模型在实验室测试集上表现很好放到虫情灯下一测掉点一大截。原因是公开照片大多是微距拍摄、背景干净、虫子完整而灯下照片往往是俯拍、带阴影、多目标粘连、部分肢体残缺。所以我一般把数据来源拆成三块第一块是灯下现场模拟拍摄用测报灯或接近的灯光环境将采集的昆虫样本撒在白板上俯拍覆盖不同姿态、不同密集程度、不同损坏程度。这一块比例应该占全部数据的一半以上否则模型学不到真实现场分布。没有条件的可以拿手机架在固定高度拍用白纸当底板尽量还原俯拍角度。第二块是公开害虫数据集比如IP102这类农业害虫集合主要用来补充类别多样性和做预训练但要注意公开数据集里的图像拍摄角度、背景颜色都和灯下差异很大不能当作主力训练数据否则会产生严重的域偏移。第三块是难例专门挑那些模糊、过曝、目标极小、多目标交叠、虫体断裂粘连的图。很多教程会让你把这类脏图直接删掉但我会把这些图保留下来作为训练集的一部分因为现场识别时最怕的恰恰是这些难例。单独给模型喂一批脏图能有效降低误检率和漏检率。2.3 标注落地Labelme 转 YOLO 格式的脚本与类别边界标注阶段建议用 Labelme 或 X-AnyLabeling 画框然后转成 YOLO 的 txt 格式。画框时有一个原则只标可见完整虫体若虫体被遮挡超出 50%则不标或者单独标一个“其他昆虫”类。这样做的原因是YOLO 在训练时会学习到“一个框对应一个实例”频繁标注半截虫子会导致模型把残影、虫体碎片也当成目标。以下是我常用的转换脚本输入 Labelme 的 JSON输出 YOLO 格式的标注文件并顺手划分 train/val。import json, os, random from glob import glob classes [稻飞虱, 二化螟, 叶蝉, 棉铃虫, 粘虫, 其他] # 按项目实际调整 def labelme_to_yolo(json_path, out_dir, class_map): with open(json_path, encodingutf-8) as f: data json.load(f) img_w, img_h data[imageWidth], data[imageHeight] txt_name os.path.basename(json_path).replace(.json, .txt) save_path os.path.join(out_dir, txt_name) lines [] for shape in data[shapes]: label shape[label] if label not in class_map: continue x1 min(p[0] for p in shape[points]) y1 min(p[1] for p in shape[points]) x2 max(p[0] for p in shape[points]) y2 max(p[1] for p in shape[points]) # YOLO 格式类别 中心点(x,y) 归一化 宽高(w,h) 归一化 cx (x1 x2) / 2 / img_w cy (y1 y2) / 2 / img_h bw (x2 - x1) / img_w bh (y2 - y1) / img_h lines.append(f{class_map[label]} {cx:.6f} {cy:.6f} {bw:.6f} {bh:.6f}) with open(save_path, w, encodingutf-8) as f: f.write(\n.join(lines)) class_map {name: i for i, name in enumerate(classes)} for j in glob(json/*.json): labelme_to_yolo(j, labels, class_map) files glob(images/*.jpg) random.shuffle(files) split int(len(files) * 0.85) with open(train.txt, w) as f: f.write(\n.join(files[:split])) with open(val.txt, w) as f: f.write(\n.join(files[split:]))脚本的核心逻辑是先读取 Labelme 的多边形坐标取最小外接矩形转成 YOLO 需要的中心点坐标和宽高全部归一化到 0 到 1 之间。注意 class_map 的顺序必须和后面的 data.yaml 保持一致并且一旦训练开始就不要再改动类别顺序否则已生成的标注文件和权重全部作废。train.txt 和 val.txt 里写的是图片的绝对或相对路径YOLO 会根据这个路径找到同级目录下的 labels 文件。类别边界也要认真定义同一种害虫的不同龄期、不同大小可以归为一类不同种但外观极其相似且实际防治手段一致的也可以先归并成大类。宁可用 8 个类把现场区分清楚也不要用 20 个类让模型反复横跳。3. YOLOv8 训练自己的数据集最小命令、参数表与损失曲线检查3.1 环境配置与最小训练命令YOLOv8 的环境配置没有想象中复杂不需要手动编译 CUDA 算子安装 ultralytics 库后新手也能直接跑起来。建议用 Python 3.10 或 3.11先建一个独立环境避免依赖冲突。训练命令如下conda create -n yolo python3.10 -y conda activate yolo pip install ultralytics torch torchvision yolo detect train data/path/to/data.yaml \ modelyolov8s.pt \ epochs150 \ imgsz1280 \ batch8 \ project./run_agri \ nameinsect_light \ workers4 \ pretrainedTrue第一行是创建环境第二行安装核心依赖。ultralytics 会自带 YOLOv8 的网络结构定义和预训练权重。modelyolov8s.pt 表示使用 small 版本作为起点如果类别少、目标大也可以改成 yolov8n.pt 或 yolov8m.pt。imgsz1280 是为了照顾虫情测报灯照片里小目标多的情况若你的相机视野大且虫子占比很小建议不要盲目用 640下面会有详细说明。data.yaml 是训练入口文件内容格式如下class 列表顺序必须和标注脚本里的 class_map 完全一致。train: /data/insect/train.txt val: /data/insect/val.txt nc: 6 names: [稻飞虱, 二化螟, 叶蝉, 棉铃虫, 粘虫, 其他]3.2 超参表关键参数怎么设才不翻车很多初学者只调 epochs 和 batch其余全用默认值这在虫情项目里容易出问题。以下是我在这个场景下常用的参数表参数建议值说明modelyolov8s.pt8 个类别以下用 n 或 s 就够类别多或目标小再用 mimgsz1280兼顾小目标召回显存不够就 960 或 640 切图推理epochs120~200看 loss 是否还有下降趋势不能只看训练集精度batch8~16显存 8G 用 816G 用 16太大不代表更好lr00.003~0.01迁移学习微调用 0.005 左右比较安全optimizerAdamW / SGD数据噪声大时 SGD 更稳AdamW 收敛快一点workers4~8Windows 下建议 4过高容易卡死Linux 可拉到 8mosaic0.5~1.0数据增强虫体密集场景建议保留但验证时关闭close_mosaic10最后 10 个 epoch 关闭 mosaic减少对脏训练数据的依赖degrees45测报灯下虫体朝向随机角度旋转增强很有用最值得强调的争议点是 imgsz。640 在多数目标检测任务里够用但虫情测报灯照片的虫子常常只有几十个像素宽直接用 640 会丢失大量细节。我实测下来相同训练数据下1280 输入的 mAP50 比 640 通常高 3 到 7 个点代价是显存占用和推理耗时也翻倍。如果现场是 RK3588 这类边缘设备建议训练时用 640 或 960导出模型后再用预处理切图推理来弥补小目标问题而不是在边缘设备上硬推 1280 分辨率。3.3 损失曲线怎么看别只盯 mAP训练时不要只看终端里的 mAP50 和 mAP50-95那只是结果不是诊断。要判断模型是否正常收敛需要关注训练过程中的四项损失box_loss、cls_loss、dfl_loss以及各自对应的验证集损失。如果训练集损失持续下降、验证集损失中途回弹说明过拟合如果两个都没怎么动说明学习率太低或数据有问题。ultralytics 会把每次训练的结果写入 run 目录下的 results.csv我习惯直接用 pandas 读出来画曲线这样可以快速判断调参方向。import pandas as pd import matplotlib.pyplot as plt df pd.read_csv(run_agri/insect_light/results.csv) df df.rename(columnslambda x: x.strip().replace( , )) fig, ax plt.subplots(2, 2, figsize(12, 8)) ax[0, 0].plot(df[epoch], df[train/box_loss], labeltrain_box) ax[0, 0].plot(df[epoch], df[val/box_loss], labelval_box) ax[0, 1].plot(df[epoch], df[train/cls_loss], labeltrain_cls) ax[0, 1].plot(df[epoch], df[val/cls_loss], labelval_cls) ax[1, 0].plot(df[epoch], df[train/dfl_loss], labeltrain_dfl) ax[1, 0].plot(df[epoch], df[val/dfl_loss], labelval_dfl) ax[1, 1].plot(df[epoch], df[metrics/mAP50], labelmAP50, colorred) ax[1, 1].set_title(mAP50) for a in ax.flatten(): a.legend() plt.tight_layout() plt.savefig(loss_curve.png, dpi150)这段代码的作用是把 results.csv 里的损失曲线画成一张图。需要注意的是ultralytics 的 results.csv 列名在不同版本里略有差异建议先用 df.columns 打印一遍看实际列名再改代码里的字符串。判断收敛的标准不是曲线是否完全拉平而是验证集 loss 不再持续下降、mAP50 开始小范围抖动时就可以停止训练。4. 从 .pt 到现场可视化界面与 RK3588 部署路径4.1 先用 Gradio 搭一个可视化识别界面标题里带可视化界面最省事的方案不是写 PySide6 桌面程序而是用 Gradio 或 Flask 做带上传和相机拍照入口的网页界面。Gradio 的好处是代码量小、自带组件、容易截图进论文和答辩。以下是我常用的版本import gradio as gr from ultralytics import YOLO model YOLO(best.pt) def detect(image, conf): results model.predict(sourceimage, confconf, imgsz1280, iou0.45) annotated results[0].plot() counts results[0].boxes.cls.tolist() names results[0].names count_text {} for c in counts: name names[int(c)] count_text[name] count_text.get(name, 0) 1 return annotated, count_text demo gr.Interface( fndetect, inputs[gr.Image(typepil, label上传灯下照片), gr.Slider(0.1, 0.7, value0.25, label置信度阈值)], outputs[gr.Image(label识别结果), gr.JSON(label计数统计)], title农田虫情测报灯害虫识别, ) demo.launch(server_name0.0.0.0, server_port7860, shareFalse)这段代码的核心是 model.predict 里的 conf 和 imgsz。界面里保留置信度滑条是给现场调试用的不同的灯位、不同的虫子密度最优阈值是不一样。结果图通过 results[0].plot() 直接画框计数统计用 boxes.cls 统计每个类别出现的次数。Gradio 的 launch 参数里 server_name 设为 0.0.0.0 是为了方便同一局域网内访问但生产环境不建议长期开着调试模式最好由后端进程拉起。真正要部署到现场时我会把这个识别函数单独抽出来封装成服务接口界面只做展示和手动复核。4.2 部署到 RK3588导出 ONNX 再转 RKNN虫情灯现场不一定有高性能 GPU常见的做法是把模型部署到 RK3588 这类边缘算力设备上。部署路径分为三步把 .pt 导出成 ONNX再把 ONNX 转成 RKNN最后用 RKNN-Toolkit2 在开发板或宿主机上做推理验证。yolo export modelbest.pt formatonnx opset12 imgsz640 pip install rknn-toolkit2 python convert_rknn.py导出 ONNX 是最容易踩坑的一步。opset 不建议太高RKNN-Toolkit2 对高版本 ONNX 的支持往往滞后用 opset 12 或 13 比较稳。imgsz 必须和后续 RKNN 转换时的输入尺寸完全一致不要训练时用 1280、导出时用 640这样会先缩放再推理目标位置偏移。转换脚本通常做这几件事加载 ONNX 模型、设置输入尺寸、量化数据集准备、输出 RKNN 文件。量化数据集一般取 50 到 200 张代表性图片覆盖不同光照、不同虫种、不同密度。这一步不是随便拿几张图凑数量化集的分布越接近现场数据INT8 量化掉点越少。如果对精度敏感可以先尝试 FP16 或混合量化RK3588 的 NPU 对 INT8 支持更高效但虫体目标小量化掉点常常在 5 到 10 个点必须实测后决定。最后推理时还有一个容易忽略的点RKNN 预处理和 YOLO 训练预处理要一致。YOLOv8 官方训练时对输入做的是 RGB 归一化到 0 到 1很多 RKNN 部署教程默认 BGR 和 /255.0一旦顺序反了模型输出乱飘但又不完全错排查起来很耗时间。建议在转换脚本里显式写入预处理参数不要依赖默认值。4.3 置信度阈值与 IOU 阈值现场取舍模型训练好后很多人直接把测试集最优阈值搬到现场这是另一个坑。虫情灯识别有明确的两类错误成本漏报会让害虫高峰预警失真误报会污染统计曲线。不同场景的阈值表可以参考下面这份经验值现场情况confiou说明背景干净、白光均匀0.250.45默认值白板有污渍、灰尘0.350.45需要压误报密集虫体场景0.250.30降低 NMS 合并强度避免粘连目标被吞夜间补光偏暗0.200.45信号弱先保召回再由人工复核做趋势曲线而非精确计数0.300.45对峰值更敏感忽略零星检测阈值调整后一定要重新看一遍验证集曲线不要只调一两个值就完事。现场如果有历史照片最理想的做法是把最近一周的灯下照片单独切出来当验证集验证集指标不达标就不准上线。5. 避坑清单五个现象、原因与现场排查顺序5.1 现象一白板过曝虫子被“洗”成白影测报灯补光灯在近距离照射下白色拍照板很容易过曝虫体轮廓和背景融为一体模型怎么调都学不好。原因不在模型而在成像端曝光设置不对。解决把相机曝光、增益、白平衡全部固定为手动不要用自动模式。先用光圈优先确定基准曝光然后缩小一档曝光量保证白色板不过曝的同时保留虫体边缘。现场可以放一张标准色卡做参考每次巡检时拍一张色卡图确认曝光没有漂移。5.2 现象二训练集里白天图太多夜间现场掉点公开数据集大多是白天自然光拍摄如果训练数据里这种图占比超过一半模型会学到“背景纹理”这个错误特征一旦现场变成灯下夜景识别率骤降。这属于数据集分布问题不是模型问题。解决按比例强制约束训练集结构灯下模拟图至少要占 60% 以上公开数据集只用来补充类别且要控制不超过 30%。划分数据时按照来源分组不要让同一个来源的图片同时出现在训练集和验证集否则验证集分数虚高现场表现缩水。5.3 现象三灰尘、水滴、枯叶被当成害虫计数灯下白板不是只有虫子还会有灰尘颗粒、水渍、草屑、蜘蛛网。模型如果没有见过这些负样本很容易把它们认成小目标虫子。解决在数据集中增加一个“其他”类把所有非昆虫杂物都标进去。把现场收集到的无虫照片直接作为负样本图片放到训练集中不需要标任何框让模型学会输出空结果。这一步对实际虫害统计非常重要很多现场部署后误报率高的项目最后查下来都是缺负样本。5.4 现象四虫体粘连严重漏检率异常高多只虫挤在一起时YOLO 可能会把它们合并成一个框或者干脆漏检。原因是训练数据里多目标交叠样本不足加上 NMS 的 iou 阈值过高粘连目标互相抑制。解决标注时不要把交叠目标拆掉按可见部分分别标框训练时把 iou 阈值从默认 0.45 调到 0.30 到 0.35减少相互抑制。再在数据增强里增加旋转、缩放和随机裁剪粘贴用来模拟密集场景。5.5 现象五验证集 mAP 很高现场每张图都冒出奇怪误检这类问题通常发生在训练集和验证集来自同一个拍摄批次的情况下。模型可能训练得不错但现场相机分辨率、安装高度、视角稍有变化域偏移就让误报放大。解决部署前先拿现场相机实拍 100 张图做快速测试统计每张图的平均检测框数量和置信度分布不要只看 mAP。尽量用现场照片做增量微调保持原始参数不变用小学习率冻结骨干层微调 30 到 50 轮。6. 别急着堆模型先建一个可复核的识别基线当你把前面几步都跑通后剩下的问题往往不是“模型精度不够”而是“模型输出怎么被验收”。虫情灯项目最容易被忽视的环节是缺少人工复核闭环。我习惯的做法是在可视化界面旁边留一个“抽样复核”按钮每天随机抽当天图片的 10% 交给植保人员看一眼把误检、漏检记录生成一条反馈数据再把这些反馈数据合并进下一轮微调训练集。这比反复调整模型结构更快见效。进阶动作通常有三个第一是把相似且防治方法一致的类别归并成科级或大类例如把几种夜蛾统一为“夜蛾类”模型难度降低现场统计反而更符合植保需求第二是用小目标切片推理把 1280 原始图切分成四张 640 子图分别推理再合并能在不增加训练负担的情况下找回一部分小目标第三是训练结束后用测试集做一次逐类 AP 排序优先补采 AP 最低类别的现场照片而不是盲目增加所有类别的样本量。我踩过最深的教训是第一版直接用 YOLOv8x 当主力模型显存吃满训练耗时翻倍精度并没有明显提升后来换成 yolov8s 1280 输入 合理数据增强反而把 mAP 拉了上来。对这类单摄像头的固定场景模型容量不是稀缺资源高质量的数据分布才是。先做小模型基线用数据补齐短板再考虑升级模型这才是虫情测报灯这类小目标项目最靠谱的路线。希望帮到你。本文还有配套的精品资源点击获取