基于YOLOv8的虫情测报灯害虫识别系统实战:从数据集到部署
发布时间:2026/9/28 6:27:16来源:尧图网络
简介基于YOLOv8的农田智能虫情测报灯害虫种类识别系统面向计算机视觉、人工智能及相关专业学生、教师和毕设开发者可完成害虫检测、模型训练与可视化分析。资源包共8个文件含3个Python源码、3个模型权重文件和2个说明文档整体约15.91MB源码按训练、检测和可视化界面拆分配合说明文档即可快速部署运行或进行视频检测适合课程设计、毕业设计及项目初期演示。内置完整数据集与可视化页面支持输出核心指标曲线、混淆矩阵、F1分数曲线、精确率-召回率曲线、验证集预测结果和标签分布图可快速验证算法效果并充实答辩展示。代码经测试运行成功处理流程完整部署提示中给出了基本的运行说明适合基础一般或希望缩短开发周期的用户直接学习、修改与复用。目前已有65人学习下载作为实用型毕设方案具备较高参考价值。1. 虫情测报灯识别系统在解决什么问题一夜几千张诱虫照片不能靠人眼数农田智能虫情测报灯一晚上能拍几千张诱虫照片如果靠人工对着屏幕数虫三四个县的点位就能把一个人钉死在工位上。这套基于YOLOv8的虫情识别系统做的就是把这些照片自动识别成具体害虫种类并计数测报灯负责诱虫和拍照YOLOv8负责把照片里的稻飞虱、二化螟、棉铃虫这些目标框出来可视化界面负责把识别结果变成能汇报的图表。它的应用场景很明确——虫情监测站、植保站的日常测报以及高校里做植保信息化方向的毕业设计。你拿到的是配好源码、界面、数据集和部署教程的完整项目剩下的工作集中在两件事把数据集换成自己田块的虫相把阈值和模型参数调到自己实验地的实际光照上。这篇笔记按一条完整落地链来讲数据集怎么整理、模型怎么训、界面怎么搭、部署会踩哪些坑、最后用什么方法验证系统真的可用。2. 整理测报灯数据集先把 labelme 标注转成 YOLO 的 txt再处理类别不平衡虫情识别系统的下限由数据集决定不是由模型决定。测报灯拍回来的原图有特点夜间灯诱、背景是黑布或白幕、虫体密集、同一帧里常有好几类虫挨在一起。直接拿网上随便下载的昆虫图片训练到现场大概率翻车因为分布完全不一样。所以拿到项目里的完整数据集之后第一件事不是急着训练而是先搞清楚它的目录结构和标注格式。2.1 训练集、验证集要按“灯位日期”分组切分不要随机打散图片很多人在划分数据集时习惯把全部图片随机 shuffle 后按比例切这在虫情识别里是个隐蔽的坑。测报灯是定时拍照的同一只虫可能出现在相邻两帧里如果这连续两帧一张进训练集、一张进验证集验证分数会虚高模型实际部署后又没这么好看。正确做法是按“灯位拍摄日期”分组整组划分让相邻帧待在同一个集合里。import os import random import shutil from collections import defaultdict # 假设原始照片命名格式为: L01_20240521_0330.jpg # 含义分别是 灯号L01、日期20240521、拍摄时间0330 groups defaultdict(list) for f in os.listdir(source_images): if not f.endswith(.jpg): continue parts f.rsplit(_, 2) # 拆成 [L01, 20240521, 0330.jpg] key parts[0] _ parts[1] # 用 灯号_日期 作为分组键 groups[key].append(f) keys list(groups.keys()) random.shuffle(keys) n_train int(len(keys) * 0.8) n_val int(len(keys) * 0.1) for i, key in enumerate(keys): if i n_train: dst_dir datasets/pest/images/train elif i n_train n_val: dst_dir datasets/pest/images/val else: dst_dir datasets/pest/images/test os.makedirs(dst_dir, exist_okTrue) for f in groups[key]: shutil.copy(os.path.join(source_images, f), os.path.join(dst_dir, f))这套逻辑的关键在rsplit(_, 2)它把文件名按最后一个分隔点拆成三段保证灯号和日期被完整取出。验证集占比我一般压到 10% 左右因为虫情照片同质度高验证集太大反而浪费标注数据。测试集可以留 10%用来做最终答辩时的效果展示不会参与训练调参。2.2 labelme 多边形标注转 YOLO 矩形框取外接矩形并归一化项目的标注数据多为 labelme 的 JSON 格式而 YOLOv8 需要的是每张图对应一个同名 txt一行一个目标格式是类别id x_center y_center width height。转换脚本我一般写成只读 JSON、直接输出 txt不改动原始标注文件。import json import os # 类别到数字id的映射必须与后续 pest.yaml 里一致 class_map {稻飞虱: 0, 二化螟: 1, 玉米螟: 2, 棉铃虫: 3, 蚜虫: 4, 甜菜夜蛾: 5, 斜纹夜蛾: 6} def convert_labelme(json_path, out_txt_path, 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] x_min, x_max min(xs), max(xs) y_min, y_max min(ys), max(ys) # 转 YOLO 归一化坐标 x_center ((x_min x_max) / 2) / img_w y_center ((y_min y_max) / 2) / img_h w (x_max - x_min) / img_w h (y_max - y_min) / img_h lines.append(f{class_map[label]} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) with open(out_txt_path, w, encodingutf-8) as f: f.write(\n.join(lines))这段脚本有两个容易出错的地方。一是encodingutf-8必须写Windows 下不指定编码读 JSON 大概率直接崩二是多边形只取外接矩形如果标注时把虫体和触角都圈进去矩形框会明显偏大识别时容易把相邻目标并成一个框。建议在整理数据集时统一标注规则只框虫体躯干不延伸翅膀和触须。2.3 类别不平衡会直接压死少数类先重采样再进训练农田场景的虫相高度不均衡。诱虫灯一亮稻飞虱可能占六成样本斜纹夜蛾只有零星几个。YOLOv8 虽然内置了 mosaic 增强但增强不能凭空造出模型没见过的目标分布少数类照样被压制。处理办法不外乎三种组合使用。最常见的是对少数类做复制粘贴增强把样本量最小的几个类从原图裁出来粘贴到同一张灯的纯色区域生成新图片。做法是写一个离线脚本把少数类的目标对象切出后随机贴在深色底板上贴完再重新标注。其次是控制训练时每个 batch 里的类别比例可以用ultralytics自带的class_weight参数但实际效果有限我一般配合离线增强一起用。最后是调低检测阈值部署推理时对少数类单独用更低的conf比如多数类用 0.25少数类用 0.15代价是假阳性变多但至少不会让系统对某一类完全失明。数据质量把关要做到一个底线每张训练图打开后对应 txt 文件里的框必须能重叠到目标上。项目自带的完整数据集最好自己抽样看一遍标注框错位严重的建议直接删掉不要指望模型自己纠正。3. 训练 YOLOv8 害虫识别模型选哪个版本、参数怎么设、损失函数怎么看模型选型和训练参数直接影响测报灯识别系统的上限。虫情照片不是普通目标检测数据集虫体小、密度高、背景单一这些特点使得参数默认值并不总是适用。3.1 模型选型n、s、m 怎么选YOLOv8 系列按体积分为 n、s、m、l、x 五档。毕设和课设场景我只推荐 n 或 s。理由很实际测报灯端侧往往是 CPU 或者老旧的 GTX 1660Ti 级别显卡n 模型在 CPU 上跑 640 输入大约能到每秒一张左右s 模型就要慢一半。而虫情照片里的虫体目标很小分辨率通常要用到 1280输入变大后推理代价成倍上涨选 l 或 x 基本等于放弃实时性。另一个角度看精度。m 模型相比 s 在 mAP 上大概能高两个点但在灯诱这种背景干净的场景里差距主要来自小目标召回率而不是分类能力。如果你手上的数据集只有几千张图选 m 反而容易过拟合验证集分数好看到了新灯位就露馅。我一般先用yolov8n.pt预训练权重做一版快速验证确认流程没问题再换 s 训练最终模型。3.2 数据集配置文件与训练命令每个参数都对应一个现场问题训练前需要准备一个 YAML 文件内容和前面的类别映射必须完全一致。# pest.yaml path: datasets/pest # 数据集根目录 train: images/train # 训练集图片目录 val: images/val # 验证集图片目录 nc: 7 # 害虫类别数 names: 0: 稻飞虱 1: 二化螟 2: 玉米螟 3: 棉铃虫 4: 蚜虫 5: 甜菜夜蛾 6: 斜纹夜蛾注意到这里没有写test字段。ultralytics 在训练阶段只读train和val测试集是自己预留出来做终验的不放进训练流程避免超参数绕回过测试集。训练命令我一般这样起from ultralytics import YOLO model YOLO(yolov8s.pt) # 加载预训练权重 model.train( datapest.yaml, epochs150, imgsz1280, # 输入分辨率小目标多不要用默认640 batch8, patience20, # 连续20轮验证指标不涨就早停 lr00.001, # 初始学习率调低更稳妥 augmentTrue, projectruns/detect, namepest_yolov8s, seed42 )关键参数逐个说清楚。imgsz1280是虫情识别和普通检测最大的区别。虫体在整幅图中的占比常常只有几十个像素640 输入下这些小目标在特征图里只剩一两个像素点几乎不可能被召回。提到 1280 后小目标召回率明显上升代价是显存占用翻倍8G 显存跑 1280 只能用 batch 8如果用 16G 以上可以提到 batch 16。patience20表示连续 20 轮验证集指标不更新就提前结束。这个值在虫情数据集上要稍微放大因为数据噪声大指标曲线会有抖动偶尔连续七八轮不涨之后又突然跳高。用默认的 10 容易早停在半成品模型上。lr0默认是 0.01我习惯降到 0.001虫情数据集通常只有几千张学习率太高容易震荡损失曲线会出现锯齿状。训练结束后在runs/detect/pest_yolov8s目录下能看到weights/best.pt和weights/last.pt。best.pt是验证集上表现最好的版本部署就用它。3.3 损失函数曲线怎么看数值大小不重要趋势才重要训练完第一件事不是看 mAP而是打开损失曲线图。ultralytics 会在results.csv里记录每一轮的train/box_loss、train/cls_loss、train/dfl_loss以及对应的验证损失画曲线图可以直接用项目自带的results.png也可以自己写脚本读 CSV。要盯着的是验证损失和训练损失的间距。如果两者都下降且间距不大说明模型还没过拟合可以继续训练或加大 epochs。如果训练损失还在降、验证损失开始掉头向上这是典型的过拟合信号这时候再训练只会让模型记住训练集的光照和虫体姿态到了新灯位就失灵。如果验证损失从第 10 轮开始就一路横盘问题往往不在训练轮数而在数据本身比如标注噪声或者类别不平衡。一个小技巧把train/box_loss和val/box_loss画在同一个坐标系里看剪刀差。剪刀差开始扩大的那个点就是模型从“学规律”转向“背答案”的分界线最终模型取这个点附近的权重更抗过拟合。3.4 训练中途翻车的常见处理训练中最常见的三个问题显存爆掉、loss 变成 nan、某个类别完全不激活。显存不够时优先降batch不要先降imgsz。虫情识别的小目标全靠 1280 分辨率撑着降分辨率等于自废武功。loss 出现 nan 时检查数据集里有没有全零的标注行比如某张 txt 里写的是0 0 0 0 0归一化后宽高为零会让损失计算出现除零。处理办法是启动前扫一遍所有 txt把包含零宽高的行删掉。某个类别完全不激活时回到第 2 章做少数类重采样模型层面通常无解。4. 可视化界面用 Gradio 把识别结果变成虫量统计现场演示也能用标题里强调可视化界面毕设答辩时这一部分最能直观展示工作量。常见的实现方式有两种PyQt5 和 Gradio。PyQt5 做出来的更像传统软件但窗口布局、按钮事件、多线程处理要写大量胶水代码一个界面从搭框架到跑通至少两天。Gradio 是 Web 界面拖拽上传、实时返回结果代码量只有 PyQt5 的五分之一适合课程设计和毕设的展示场景部署也便宜一台老笔记本就能跑起来。我推荐用 Gradio 做虫情识别的可视化界面既能传图识别也能返回每类害虫的数量统计现场演示时还能用滑杆动态调整置信度阈值。4.1 界面代码识别图片并输出虫量统计import gradio as gr from ultralytics import YOLO model YOLO(runs/detect/pest_yolov8s/weights/best.pt) def predict(img, conf_threshold): # 推理时关闭数据增强保证结果可复现 results model.predict( img, confconf_threshold, imgsz1280, devicecpu, # 现场机器没有GPU也能跑 augmentFalse, verboseFalse ) boxes results[0].boxes names results[0].names # 按类别统计数量 count {} for cls_id in boxes.cls.tolist(): name names[int(cls_id)] count[name] count.get(name, 0) 1 plotted results[0].plot() return plotted, count gr.Interface( fnpredict, inputs[ gr.Image(typepil, label上传测报灯照片), gr.Slider(0.05, 0.9, value0.25, step0.05, label置信度阈值) ], outputs[ gr.Image(typenumpy, label识别结果), gr.JSON(label害虫数量统计) ], title农田虫情测报灯害虫种类识别系统 ).launch()这段代码做了三件事加载训练好的 best.pt 权重、对上传图片做推理、把结果整理成框选图和 JSON 数量统计。devicecpu是为了现场演示时不受显卡限制单张 1280 图在 CPU 上大约需要几秒演示节奏完全能接受。augmentFalse很重要如果不关掉同一张图每次推理结果会有细微波动答辩时容易被追问。conf_threshold滑杆直接暴露给使用者就是让现场可以演示误报和漏报的权衡阈值拉高框变少但准确率高阈值拉低框变多但会出现把灯下阴影识别成害虫的情况。对于虫情测报而言计数任务更怕漏报所以我默认给 0.25比通用检测的 0.25 还要再往低压一点实际使用按田块特点微调。4.2 灯诱照片的预处理光晕和暗角影响识别界面上加一个增强开关测报灯的照片有明显的物理特征灯管周围过曝形成光晕画面四周偏暗虫体翅膀在强光下反光。这些都会让识别框位置偏移。常见做法是在推理前对图像做 CLAHE 对比度增强把过曝和暗部的细节同时拉回来。import cv2 import numpy as np def enhance_image(img): # 转到LAB色彩空间只增强L亮度通道避免颜色偏移 lab cv2.cvtColor(img, cv2.COLOR_RGB2LAB) l, a, b cv2.split(lab) clahe cv2.createCLAHE(clipLimit2.0, tileGridSize(8, 8)) l_enhanced clahe.apply(l) enhanced cv2.merge([l_enhanced, a, b]) return cv2.cvtColor(enhanced, cv2.COLOR_LAB2RGB)clipLimit2.0是经验值数值太大会把背景黑布提亮成灰色产生伪目标数值太小等于什么都没做。把这段函数接到 Gradio 的predict里在统一尺寸缩放之前执行能明显提升暗部虫体的召回率。注意tileGridSize用 8x8 就好过大图像会变成块状斑驳。5. 部署与避坑CPU 环境怎么跑、5 个高频踩坑记录部署教程是这个项目里最值钱的部分。别人给你的权重文件再准环境搭不起来等于零。这一章先给出一套可以照抄的部署流程再把实际部署中遇到的高频问题按现象、原因、解决三个层次写清楚。5.1 部署环境先建独立 conda 环境CPU 机器也能跑完整流程部署不一定需要 GPU。虫情识别的应用场景是测报站定时处理照片单张推理时间在几十秒内都能接受CPU 足够用。以下命令在 Ubuntu 20.04 和 Windows 10 上均可执行区别只在 torch 的安装方式。conda create -n pest python3.10 -y conda activate pest # CPU 版本 torch安装包约 200MB不需要 CUDA 环境 pip install torch2.1.2 --index-url https://download.pytorch.org/whl/cpu # 安装 ultralytics 和界面依赖 pip install ultralytics gradio onnxruntimeUltralytics 会自动拉取匹配的 opencv-python 和 numpy 版本不需要手动指定。装完后先用python -c from ultralytics import YOLO; print(YOLO(yolov8n.pt))验证模型能否加载能加载说明环境没问题。如果本机有 NVIDIA 显卡把 torch 安装命令换成pip install torch2.1.2 cu121或者直接用pip install torch自动匹配其余不变。GTX 1660Ti 跑 1280 输入的 s 模型推理时间大约在 100 到 200 毫秒配合界面完全没有压力。如果后续要往边缘设备上部署比如 RK3588 这类开发板环节会多一个模型转换先导出成 ONNX再转成 RKNN。这部分工作量大在算子兼容建议先用 CPU 版把整套系统跑通再考虑边缘化。5.2 五个高频踩坑记录按“现象—原因—解决”整理踩坑一验证集 mAP 高达 0.9换一个灯位的照片就成灾难现场。现象是模型在项目自带验证集上表现惊人拿到自己拍的照片后漏检严重。原因基本可以锁定数据集划分不当同一个灯同一晚的连续帧被同时分进训练集和验证集验证分数是“背题”背出来的不是真实泛化能力。解决方法是按第 2 章的“灯位日期”分组重新划分划分后重新训练。这一点要在拿到数据集后第一时间检查血泪经验。踩坑二稻飞虱类全被识别成棉铃虫少数类完全消失。现象是训练时损失函数正常下降但某个类别在预测结果里从不出现在第一候选。原因是样本量差距悬殊模型在多分类损失里更偏向高频类别。解决思路分两步走先给少数类做复制粘贴增强将样本量拉到多数类的三分之一以上再对少数类单独设置低推理阈值。不能只调模型参数那是把希望寄托在随机性上。踩坑三夜间光晕区域的虫子一直漏检。现象是图中央灯管周围几乎没有检测框或者框的位置偏向一侧。原因是测报灯灯管周围过曝虫体与背景的对比度被强光抹平模型学到的边缘特征失效。解决方法分两种推理前用 4.2 节的 CLAHE 增强或者训练时在数据增强里加入随机亮度扰动让模型见过更多过曝变体。如果项目时间紧直接用 CLAHE 增强不用重新训练。踩坑四界面推理卡顿滑动阈值后要等很久才出结果。现象是 Gradio 界面第一次加载模型要等几十秒后续推理也慢现场演示体验不好。原因是devicecpu之外没有做任何加速找了一张高分辨率原图直接塞进 1280 输入。处理办法有两个一是把图片先缩放到 2048 以内再做imgsz1280的推理二是提前加载模型不要在每次推理时重复调用YOLO()构造函数。模型加载耗的是 I/O 和反序列化时间放全局初始化一次就好。踩坑五Windows 下运行训练或界面时中文标签乱码。现象是训练日志里的类别名乱成一团或者界面返回的虫名变成问号。原因是终端和 Python 的默认编码不一致。解决方法是训练脚本开头加上import sys sys.stdout.reconfigure(encodingutf-8)同时在 pest.yaml 的names字段里直接用中文写类别名ultralytics 会同步到界面输出不需要额外映射英文名。如果界面仍然乱码把系统区域设置里的 UTF-8 Beta 版打开或者干脆在界面代码里对输出做一次str.encode(utf-8).decode(utf-8)强制转码。部署阶段另一个容易忽略的是显卡驱动版本和 PyTorch 版本的匹配问题。如果遇到CUDA out of memory先确认 torch 能识别到 GPU 再排查显存设置如果driver version is insufficient说明驱动太老直接更新驱动比折腾 conda 环境更省时间。6. 验证系统真的能用逐类看 mAP、导出 ONNX 降门槛、切片推理补小目标训练完模型、搭好界面最后一步是验证这套系统在真实测报灯照片上的表现。常见的误区是只看总 mAP虫情识别必须逐类看因为总 mAP 会被优势类拉高少数类的劣化被埋没。from ultralytics import YOLO model YOLO(runs/detect/pest_yolov8s/weights/best.pt) metrics model.val(splitval, imgsz1280, conf0.25) # 逐类打印 mAP50-95不要只看总 mAP for i, name in metrics.names.items(): print(f{name}: {metrics.box.maps[i]:.4f})metrics.box.maps是每个类别单独的 mAP50-95 列表数值越低说明该类越需要额外数据或更低阈值。我自己的习惯做法是把这个输出和混淆矩阵图保存在项目目录里答辩时可以拿出来讲清每个类别的性能边界比一句“准确率 95%”有说服力得多。验证完后做一次 ONNX 导出。这也是部署到边缘设备的第一步同时能摆脱对完整 PyTorch 环境的依赖运行机器只需要onnxruntime一个包。model.export(formatonnx, imgsz1280, opset12, simplifyTrue)导出后的 best.onnx 在 CPU 上推理速度比 PyTorch 模式快一截。需要注意 YOLOv8 导出的 ONNX 输出是一个1x84x8400的矩阵后面要写坐标解码加 NMS这一步项目里如果预置了推理脚本就直接用没有的话按 ultralytics 的官方解码逻辑补上即可几十行代码。虫情照片还有一个大头坑原图分辨率太高直接缩放会丢失小目标。最终部署时可以用切片推理把 4000x3000 的原图按 1280 大小切四块每块推理后再把框映射回原图坐标重叠区域用置信度高的框去重。代码不复杂但能明显提高边缘区域的虫体召回率。这套系统走到这里从数据集清洗、模型训练、界面搭建到部署验证的闭环就完整了。我的习惯是每次拿到新灯位的照片先跑十张看漏检集中在哪一类再回头决定是做数据增强还是调阈值而不是直接改网络结构。模型是黑匣子但数据分布不是把精力放在能控制的地方系统的可靠性才会真正上去。希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网