ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

基于YOLOv8的虫情测报灯害虫识别系统实战指南

基于YOLOv8的虫情测报灯害虫识别系统实战指南 简介基于YOLOv8的农田智能虫情测报灯害虫种类识别系统是一套面向计算机视觉、人工智能等专业学生的毕业设计/课程设计完整方案覆盖害虫检测模型的训练、评估与可视化展示可直接用于农田虫情监测场景。资源压缩包共8个文件含3个Python脚本、3个模型权重文件与2个说明文档其中脚本分别实现可视化界面、模型训练与视频检测权重文件便于直接加载推理文档内含部署教程和运行说明整体大小15.91MB结构清晰。项目经测试可成功运行支持输出核心指标曲线、混淆矩阵、F1分数曲线、精确率-召回率曲线、验证集预测结果及标签分布图方便在答辩中直观体现模型性能与实验完整度。目前已有65人浏览学习适合需要快速落地系统的在校学生或深度学习入门者下载后按说明文档操作即可启动使用。1. 虫情测报灯遇上YOLOv8为什么害虫种类识别必须换一种做法基于YOLOv8的农田智能虫情测报灯害虫种类识别系统说白了就是让虫情测报灯把拍到的害虫照片交给深度学习模型自动按种类认出来并计数。传统测报灯每天积攒大量诱虫照片靠人工数虫、分类、录入费时易错这个系统把YOLOv8接到测报灯的图像链路上代替人力完成识别和统计。标题里的打包内容很常见一般是源码、界面、数据集、部署教程齐全号称简单部署即可运行但我得说句大实话真正跑通一个毕设项目仍需要你自己把环境、数据和模型训练这条线捋清楚。这篇博文就按这条线讲从数据准备、模型训练、界面部署到现场避坑适合正在做毕设或课程设计的同学也适合想给植保站测报灯做智能化改装的一线工程师。2. 系统架构与数据流转测报灯图像是怎么变成YOLOv8训练样本的看懂这个系统的源码之前最需要搞明白的是数据从哪来、要转成什么样子。虫情测报灯拍出来的照片和手机拍的昆虫特写完全是两类图它们的预处理方式也不一样。这一章先把硬件图像特点讲透再给出切图和标注的可复现做法。2.1 虫情测报灯的工作机制与图像特点虫情测报灯的常见结构由黑光灯、撞击屏、漏斗、传送带和摄像头组成。夜里开灯趋光性害虫扑向灯管撞到玻璃撞击屏后掉进漏斗落在下方传送带上。摄像头按设定间隔拍照拍完传送带转动换上新的一批虫子。还有一类测报灯用性诱剂配水盆摄像头拍水面上的虫子。无论哪种照片都有三个共同点背景相对干净、害虫目标小、个体数量多且经常堆叠。正是这三个特点决定了不能把YOLOv8直接套在原图上。几千像素的整张照片缩放到640后一只小飞蛾可能只剩几个像素检测器基本看不到。另外测报灯玻璃板在夜间会有灯管高光区和帘布阴影区这些局部亮度会造成误检。所以第一步不是急着训练而是先把原始图像切成小块、去掉大部分空背景和反光区域让一只害虫在一张640的小图里尽量占据可辨认的像素规模。2.2 原始照片清洗与切图用OpenCV把大图切成训练小块我一般先用OpenCV把大图按640x640切成小块切完再人工或程序过滤掉空图。下面这段脚本可以自动完成切图和简单过滤import cv2 from pathlib import Path def split_images(src_dir, dst_dir, tile_size(640, 640)): src_dir Path(src_dir) dst_dir Path(dst_dir) (dst_dir / images).mkdir(parentsTrue, exist_okTrue) for img_path in src_dir.glob(*.jpg): img cv2.imread(str(img_path)) h, w img.shape[:2] step_x, step_y tile_size for y in range(0, h, step_y): for x in range(0, w, step_x): tile img[y:y step_y, x:x step_x] # 丢弃过亮和过暗的小图这些大概率是灯管或阴影区域 if tile.mean() 10 or tile.mean() 245: continue out_path dst_dir / images / f{img_path.stem}_{x}_{y}.jpg cv2.imwrite(str(out_path), tile) if __name__ __main__: split_images(/raw_data/light_trap, /prepared_data, (640, 640))这段脚本从原始目录读取所有jpg大图按640步长切成不重叠的小图。注意step_x和step_y用了和tile大小相同的值意味着相邻块没有重叠。如果想让同一只虫子在多个块中出现可以把步长改成320代价是样本量翻倍。过滤条件tile.mean()只判断灰度均值能去掉一部分纯黑、纯白背景图但反光区域不一定能被完全滤掉后面还要在模型训练阶段用负样本去压制。切图完成后需要人工浏览一遍所有小图把没有虫子的空图删掉。这里有个偷懒技巧你可以先用一个预训练的YOLOv8通用模型跑一遍所有小图把检出框小于2个的图片列为候选空图再人工确认。虽然通用模型不认识具体害虫但对“有没有东西”的识别能力足够用来筛图。2.3 数据标注与YOLO格式组织从VOC到YOLO的转换脚本标注是害虫识别最耗时间的环节。常用工具是LabelImg或X_AnyLabeling前者轻量稳定后者支持自动半标注。建议按“一种虫一个矩形框”的方式标交叠严重的虫子允许框重叠但不要把包含多只虫的大框当成一个目标。标完的YOLO格式是这样的每个图片同名txt一行代表一个目标格式是“类别id 中心x 中心y 宽 高”前两个是归一化坐标。有些公开数据集或旧标注给的是VOC xml想转成YOLO格式可以直接用下面这段脚本import xml.etree.ElementTree as ET def voc_xml_to_yolo(xml_path, out_txt_path, class_names): tree ET.parse(xml_path) root tree.getroot() size root.find(size) img_w int(size.find(width).text) img_h int(size.find(height).text) with open(out_txt_path, w) as f: for obj in root.iter(object): cls_name obj.find(name).text if cls_name not in class_names: continue cls_id class_names.index(cls_name) box obj.find(bndbox) x1 int(float(box.find(xmin).text)) y1 int(float(box.find(ymin).text)) x2 int(float(box.find(xmax).text)) y2 int(float(box.find(ymax).text)) # 把越界的坐标拉回图像边界避免训练时出现负框 x1, y1 max(0, x1), max(0, y1) x2, y2 min(img_w, x2), min(img_h, y2) dw, dh 1.0 / img_w, 1.0 / img_h cx (x1 x2) / 2.0 * dw cy (y1 y2) / 2.0 * dh w (x2 - x1) * dw h (y2 - y1) * dh f.write(f{cls_id} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}\n)脚本核心是按图像宽高归一化并把框坐标clamp到图像内部。很多训练loss为NaN的玄学问题最后查出来都是因为标注框超出了图片边界。检查完坐标后数据集目录按下面结构组织insect/ ├── images/ │ ├── train/ │ └── val/ └── labels/ ├── train/ └── val/2.4 样本平衡与增强别让某个类别一家独大昆虫类别天然不平衡稻飞虱可能占了一半样本某种夜蛾只有几十张。直接训练模型会偏向样本多的类。常见做法是先统计每个类别的bbox数量然后对样本少的类做水平翻转、亮度抖动、随机裁剪增强。注意翻转后的YOLO标签要做坐标变换cx要变成1-cx亮度抖动则不影响标签。如果项目里已经给了完整数据集也要做一遍统计因为很多打包数据集本身就有严重的类别分布问题。3. 训练自己的害虫识别模型YOLOv8环境、命令与调参细节数据和标注就位后开始训练。这里列的是基于ultralytics YOLOv8的标准做法兼容gtx1660ti这类6G显存的显卡也覆盖yolov8训练自己的数据集时最常碰到的几个参数。3.1 环境安装适合小白的YOLOv8环境配置先用miniconda创建独立虚拟环境避免把系统python搞乱。安装PyTorch时要选对CUDA版本否则训练时会提示找不到显卡。下面是一套我常用的安装顺序conda create -n insect python3.9 -y conda activate insect # 以CUDA 11.8版本的PyTorch为例 pip install torch2.1.2 torchvision0.16.2 --index-url https://download.pytorch.org/whl/cu118 # 安装ultralytics pip install ultralytics先装PyTorch再装ultralytics因为ultralytics会依赖torch如果让它自动装可能拉来一个与你显卡驱动不匹配的新版本。如果你的电脑没有NVIDIA显卡直接用pip install torch torchvision装CPU版就行但训练速度会慢很多这种场景建议先拿小数据集验证流程再租GPU跑。安装完成后用一行命令验证python -c import ultralytics; print(ultralytics.__version__)3.2 整理数据集data.yaml写法与目录校验脚本在数据集根目录放一个data.yaml里面写类别名和路径。注意路径尽量写绝对路径因为相对路径在不同机器上容易飘。path: /home/user/datasets/insect train: images/train val: images/val names: 0: rice_planthopper 1: asian_corn_borer 2: grass_leaf_fly 3: beet_armyworm类别名用什么语言不影响训练但必须和标注txt里的id严格对齐。为了保险训练前跑一个校验脚本检查有没有越界id和空标签文件import os from pathlib import Path label_dir Path(insect/labels/train) nc 4 # 你的类别总数 for f in label_dir.glob(*.txt): with open(f) as fp: for line in fp: parts line.split() if not parts: continue cls_id int(parts[0]) if cls_id nc: print(fbad label: {f} class{cls_id})这个脚本很简单但能提前挡住大量“mAP为0”的翻车现场。3.3 训练命令与关键参数gtx1660ti如何跑得稳训练命令用yolo detect train我一般会显式把关键参数都写出来方便复现yolo detect train \ datainsect.yaml \ modelyolov8s.pt \ epochs200 \ imgsz640 \ batch8 \ device0 \ workers4 \ projectruns \ nameinsect_syolov8s在这个任务里是性价比不错的选择。如果显存只有6Gbatch设为8再低就设4不要设16否则容易爆显存。imgsz不要低于640因为害虫目标小用512会把稻飞虱这类微小型昆虫直接抹掉。训练过程可以开着tensorboard看loss但我更习惯直接看runs目录下的results.png。训练有几个默认增强参数值得注意mosaic马赛克默认是打开的它把四张图拼成一张能提升小目标泛化能力close_mosaic默认在最后10个epoch关闭让模型从完全增强过渡到真实分布这两个参数一般不用改。如果你发现loss在后期不稳定可以调低学习率lr00.001或者把batch调大一点提升收敛稳定性。3.4 评估与调优用mAP50和召回率决定下一步训练结束后验证一下权重文件yolo detect val \ datainsect.yaml \ modelruns/insect_s/weights/best.pt \ imgsz640验证结果会打印precision、recall、mAP50和mAP50-95。在害虫测报场景我强调的是recall优先漏检一只虫可能意味着漏掉一次迁入高峰的预警信号。如果mAP50达到0.9以上说明模型在验证集上已经很有区分度。如果mAP50只有0.5先别急着换网络打开runs目录下的confusion_matrix.png看看哪两类在互相混淆。常见的翻车是斜纹夜蛾和甜菜夜蛾长得接近被大量互认。这时候要么合并成“夜蛾类”要么补充更容易区分两种虫的特写数据并检查标注是否有张冠李戴。4. 可视化界面与本地部署用PyQt5把识别结果展示出来模型跑通后还要有一个操作界面。标题里的“可视化界面”通常就是给用户点选图片、看到检测框、拿到计数结果的程序。这里我用PyQt5做例子因为桌面应用在毕设答辩时演示最直接也容易打包成exe。4.1 界面选型桌面端PyQt5和Web端的取舍我在这类项目里遇到过三种界面方案各有利弊方案优点缺点适合场景PyQt5/PySide6单机离线可用能读摄像头打包成exe方便界面调试略繁琐UI美化要花时间毕设演示、田间一体机Flask/FastAPI HTML远程访问界面自由度大需要前后端一起写部署较复杂服务器统一管理多台测报灯Gradio/Streamlit几行代码出界面定制性弱不适合作为完整交付物快速demo、算法验证打包项目里通常带的是PyQt5界面因为它和YOLO模型在同进程内调用最简单。如果你打算改成Web端核心识别代码其实可以复用只是把模型推理封装成HTTP接口。4.2 PyQt5界面实现单张图片识别的可运行骨架一个最简的PyQt5识别窗口核心代码就三部分加载模型、选择图片、画框显示。下面这段骨架可以跑起来布局简化了不少但功能完整import sys import cv2 from PyQt5.QtWidgets import QApplication, QLabel, QMainWindow, QPushButton, QFileDialog from PyQt5.QtGui import QImage, QPixmap from ultralytics import YOLO class InsectApp(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle(虫情测报灯识别系统) self.btn QPushButton(选择图片, self) self.btn.move(10, 10) self.label QLabel(self) self.label.setGeometry(10, 50, 800, 600) self.btn.clicked.connect(self.open_image) self.model YOLO(best.pt) # 换成你的权重路径 def open_image(self): path, _ QFileDialog.getOpenFileName(self, 选择图片, , Images (*.jpg *.png)) if not path: return results self.model.predict(path, conf0.3, imgsz640) img cv2.imread(path) if results: r results[0] for box, cls, conf in zip(r.boxes.xyxy, r.boxes.cls, r.boxes.conf): x1, y1, x2, y2 [int(v) for v in box.tolist()] name self.model.names[int(cls)] cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(img, f{name} {conf:.2f}, (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2) rgb cv2.cvtColor(img, cv2.COLOR_BGR2RGB) h, w, c rgb.shape qimg QImage(rgb.data, w, h, c * w, QImage.Format_RGB888) self.label.setPixmap(QPixmap.fromImage(qimg).scaled(self.label.size())) if __name__ __main__: app QApplication(sys.argv) win InsectApp() win.resize(820, 660) win.show() sys.exit(app.exec_())逻辑很简单按钮点击后弹出文件挑选框把图片路径直接交给model.predict。YOLOv8会返回一个Result对象里面boxes.xyxy是四个坐标、boxes.cls是类别id、boxes.conf是置信度。把每个bin画在图片上再用QLabel显示。注意OpenCV读进来是BGR显示到Qt前必须转成RGB否则颜色会偏。这里有两个参数值得细说conf0.3是识别阈值虫情监测建议设低一点宁可多报几个框再人工复核也不要漏掉虫imgsz640要和训练时一致否则尺寸不一致会导致检测率下降。如果你的图片是从测报灯原始大图切完再识别的这里仍然传640不要传原始图的尺寸。4.3 视频流与批量目录识别让界面更贴近测报灯场景实际测报灯的摄像头通常不是一张张人工点图片而是定时拍目录下新图片。界面里可以加一个QTimer每5秒扫描一次图片文件夹并自动识别from PyQt5.QtCore import QTimer self.timer QTimer() self.timer.timeout.connect(self.scan_folder) self.timer.start(5000) def scan_folder(self): import glob for img_path in glob.glob(captured/*.jpg): results self.model.predict(img_path, conf0.3) # 写入csv或更新界面计数这样界面展示的就是连续自动识别结果还能顺带生成当天各虫类的数量台账。4.4 边缘部署从best.pt到ONNX再到RK3588如果要把识别放进测报灯旁边的边缘盒子常见选择是Jetson Nano或RK3588。最近很多人搜rk3588部署yolov8原因是这块芯片带NPU功耗低适合挂在田间。第一步用官方导出命令把权重转成ONNXyolo export modelbest.pt formatonnx imgsz640 opset12得到best.onnx后用瑞芯微的rknn-toolkit2工具把ONNX转成rknn模型注意要选择芯片对应的target平台比如rk3588。转换时通常还要固定输入尺寸、量化方式。Rknn模型在板子上用rknn-toolkit-lite加载推理可以直接拿到检测框输出。这里不展开命令因为不同rknn版本命令差异较大打包项目里的部署教程如果写清楚了跟着做就行。要提醒一句很多老式测报灯内部只有单片机根本跑不动YOLOv8工程上通常让测报灯只负责拍照图片传到后台服务器或边缘盒子识别而不是强行塞进原厂灯体。5. 害虫识别系统避坑与排查从训练翻车到现场误检的解决路径我见过太多同学卡在环境、数据和部署上明明是模型没跑起来却反复改网络结构越跑越偏。这里按“现象→原因→解决”写几条最常见的坑。5.1 训练阶段loss为NaN、mAP为0、数据加载卡死坑1训练几十个epoch后loss突然变成NaN。现象训练曲线里loss爆到1000以上或显示nan。原因学习率偏大或者标注数据里出现了越界框、类别id越界导致反向传播时数值不稳定。解决先跑一遍第二节里的标签校验脚本把类别id超过总类别的txt删掉然后把学习率降到lr00.001batch从8降到4重新训练。NaN问题八成是数据脏不是模型复杂。坑2训练完成但mAP50一直是0预测完全没框。现象评估指标全是0预测原图画上没有任何检测框。原因最常见的是类别id映射错位。比如标注文件第一列是1、2、3而data.yaml里0对应第一个类模型把类别1当成了背景自然什么都检不出。解决打开一张图片对应的txt看第一列数字再对照data.yaml里的names。如果确实错位用脚本把所有txt里的id统一减1或加1再重新验证。坑3Windows下训练卡在Loading dataset始终不进入训练。现象程序停在数据加载阶段CPU占用但进度不动。原因workers多进程在Windows下会和数据集读取冲突或者图片后缀不统一导致读取失败。解决训练参数里加workers0把数据集所有图片统一后缀为.jpg用bash或python批量改一下。这个问题在Windows上几乎必现如果你用笔记本做毕设看到卡住先别急着骂代码。5.2 部署阶段大图漏检、界面卡死、反光误检坑4测试小图识别很好但我把测报灯原图直接丢给模型检测不到虫子。现象原图是几千像素大图模型跑完一个框都没输出。原因直接把大图resize到640小目标被压没了。训练时模型看到的是切块后的图推理时也要按同样方式切块。解决推理时把大图切成640x640的块每块单独识别再把框坐标偏移回原图。核心逻辑import cv2 from ultralytics import YOLO model YOLO(best.pt) img cv2.imread(light_trap_big.jpg) step 640 for y in range(0, img.shape[0], step): for x in range(0, img.shape[1], step): tile img[y:y step, x:x step] results model.predict(tile, conf0.3, imgsz640) for r in results: for box in r.boxes.xyxy.cpu().numpy(): # 得到的是tile内的坐标需要加回偏移量 x1, y1, x2, y2 box [x, y, x, y] # 画框或记录这一步是部署到测报灯现场最容易栽的坑很多打包项目的部署教程里只写“运行demo”没写大图切块所以你要自己补上。坑5PyQt5界面点选图片后卡成“未响应”。现象点击按钮后窗口转圈识别结束才恢复。原因YOLO推理是耗时操作直接在Qt主线程里跑会阻塞窗口绘制。解决把推理放到后台线程用PyQt5的信号把结果传回主线程更新界面。最简单的做法是threading.Thread开一条守护线程跑识别识别完用QTimer或信号触发UI刷新。不用管复杂线程细节但一定要避免在主线程里做长任务。坑6玻璃反光和高光亮区被当成虫子。现象预测结果在灯管位置或玻璃边界出现一堆无意义的框。原因训练数据里这类高光背景太少模型没有把它学成背景。解决搜集一部分不带虫子的反光、阴影、水雾照片作为空样本放进训练集注意这些图片不需要标注YOLOv8会把它们当背景。另外部署时可以在界面里画一个ROI区域只识别传送带区域从根源上避开高光区。6. 让识别结果可信虫情趋势验证与识别链路的一点进阶心得6.1 如何判断系统真的可用指标与抽检复核识别系统是否可信不能只看demo里那几张图。除了验证集的mAP50我还会用每类召回率做一次人工抽检每天从测报灯照片里随机抽10%的识别记录人工核对框里的虫种和模型判断是否一致。一致率高于95%才允许系统直接上报低于这个线就降低置信度阈值或补充易混类别数据。这种复核逻辑比任何训练指标都更靠近用户需求也是答辩时能拿出手的“工程责任感”体现。6.2 从识别到趋势把结果写成CSV并绘制虫情曲线识别只是第一步虫情测报的价值在趋势。把每天识别到的各类害虫数量写入CSV再画成曲线就能看到迁飞性害虫的峰期。这里提供一个简单的结果计数写入片段import csv import time from collections import Counter def save_insect_counts(img_path, results, outputinsect_counts.csv): names list(results[0].names.values()) cls_ids [int(c) for c in results[0].boxes.cls.cpu().numpy()] counter Counter(cls_ids) row [ time.strftime(%Y-%m-%d %H:%M:%S), img_path, *[counter.get(i, 0) for i in range(len(names))] ] header [time, image, *names] with open(output, a, newline, encodingutf-8) as f: writer csv.writer(f) if f.tell() 0: writer.writerow(header) writer.writerow(row)字段按自己的类别调整。积累几天数据后用pandas读进来以日期为横轴画折线图就能直观看出每种害虫的发生曲线。这个功能是界面的加分项比单独展示一张张图更能体现“智能虫情测报”。最后说一个我的教训有一年我在优化稻飞虱测报项目训练集mAP到了0.91但一到早晨有露水的现场就漏检。后来发现是测报灯玻璃板蒙上水雾整体对比度下降模型没见过这种风格。后来加了随机对比度扰动和模拟薄雾增强并把露水时段改成只在图像清晰时触发识别问题才缓解。所以做这类系统别只盯训练指标先摸清现场条件再回来调数据。希望帮到你。本文还有配套的精品资源点击获取
返回列表