ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

昆虫识别与数目统计毕设实战:基于YOLOv8的目标检测与计数全流程解析

2026/10/5 8:12:08 拓冰建站 浏览量
昆虫识别与数目统计毕设实战:基于YOLOv8的目标检测与计数全流程解析 简介这是一份面向计算机视觉方向毕业设计的完整项目包定位为大四学生完成昆虫识别与数目统计课题的参考实现也适合课程设计、大作业选择该方向的人群借鉴初、中级开发者均能顺利上手。项目内含昆虫图像样本、Python训练与推理脚本、模型权重、图片标注文件、识别结果表格以及可视化界面覆盖数据预处理、模型搭建、训练调参、检测计数与结果导出的典型流程并配有说明文档帮助理清代码结构和使用方法。压缩包共一百六十四个文件以昆虫图像和Python脚本为主体辅以数据文件、标注文件、统计表格、图片素材及说明文档整体大小约14.59MB结构紧凑且目录层次清晰便于按模块查阅。现有约一百四十人学习下载可当作毕业设计基线快速跑通也能通过阅读源码和标注数据理解检测计数原理减少从零搭建的重复劳动。1. 昆虫识别和数目统计毕设看着简单坑全在计数后半段昆虫识别和数目统计这个毕设题第一眼很像图像分类但你拿到大四的 zip 压缩包解压后跑两步就会发现识别框能画出来数目对不上。题目的技术本质不在“识别”而在后半段——目标检测给出框数目统计是另外一套计数逻辑口径不定义清楚代码里全是“重复计数”式的假 bug。它适合课设、大作业和毕业设计尤其是需要一个能演示、能写论文、能在现场答辩讲清楚的工作流的场景。这篇笔记按我做过同类方案的顺序展开选型、数据、训练、排错最后落到能答辩的展示系统。2. 技术选型检测计数与密度估计两条路线怎么选2.1 检测后计数为什么昆虫毕设默认选 YOLO 而不是分类网络毕设里的昆虫识别很多人第一反应是用图像分类网络把每张图标成“有瓢虫”或“有蝗虫”。但题目带了“数目统计”分类网络给不出位置和数量所以常规做法是走目标检测先让模型用框把每只虫框出来再数框。这个思路在实现和答辩上都站得住——既能展示检测框可视化又能把“总数”解释成“模型预测框中置信度高于阈值的对象个数”。选 YOLO 而不是 Faster R-CNN 或 SSD理由有三个。第一YOLO 系列在 PyTorch 生态里最成熟yolo命令行和 Ultralytics 库能把训练、验证、导出一条龙串起来适合毕业设计这种时间紧、需要快速出效果的场景。第二昆虫普遍体积小YOLO 把小目标检测能力做成了默认配置把输入分辨率提到 640 甚至 1280 后漏检问题能明显缓解。第三它的日志和可视化工具比自绘的检测框架完整画 loss 曲线、画混淆矩阵都现成写论文实验部分省很多事。2.2 密度图回归路线密集虫口场景才值得碰如果你做的是虫情测报灯或粘虫板一张图上可能挤了几百只蚜虫框全部叠在一起目标检测很难数清。这时候密度图估计才有优势用一个回归网络把图片映射成密度图对整张图积分就是虫口总数典型代表是 CSRNet。代价也很明确标注方式从画框变成点选虫子预处理要把点坐标生成高斯密度图高斯核大小对结果影响很大答辩时解释起来比检测框多一层。两种路线放在一起看选型就很清楚了对比项检测后计数YOLO密度图回归CSRNet输出内容每只虫的框、类别、数量密度图、总数标注成本画框小虫费工时点选中心点快但要写生成脚本拥挤场景大量重叠时计数不准密集虫口优势明显答辩可解释性框可视化直观好讲需要解释“密度积分”对毕设的适配度高工具链完整中等适合做论文改进点我一般建议毕设默认选检测计数密度图只留作“针对密集场景的优化尝试”。这样主流程稳定又有地方可以做创新。2.3 计数口径先行单图计数与视频去重答辩前必须先定清楚很多翻车都发生在同一个问题上老师问“你这个数目统计到底统计的是什么”如果做单张图片口径是这张图里检测出的目标数量如果做视频要决定是每帧分别数还是整个视频按目标 ID 去重后的数量。口径不先定代码里就会反复出现“重复计数”的 bug其实不是 bug是需求没定义好。我常用做法是先写一个最小的计数函数把口径固定再往上接模型推理def count_insects(confs, cls_ids, names, conf_threshold0.25): 统计一张图中的昆虫数量按类别返回计数结果。 口径说明置信度低于阈值的框不计入 单张图内重叠框不做去重视频场景由跟踪模块负责。 keep confs conf_threshold cls_ids cls_ids[keep] counter {} for cls_id in cls_ids.tolist(): name names[int(cls_id)] counter[name] counter.get(name, 0) 1 counter[total] sum(counter.values()) return counter这里的conf_threshold是识别和计数共用的关键参数。调太低背景噪声会变成虫子调太高小目标被漏掉。做静态计数我一般取 0.25 到 0.35做视频计数取 0.35 以上因为连续帧能补回单帧漏检宁可少误检。names来自训练时的类别字典取错的话类别和数量会对不上。这个函数把计数逻辑从推理流程剥出来后面换视频追踪去重只改入口就行。3. 数据准备数据集选型、标注转换和划分3.1 数据集选型从 IP102 里砍出 5 个类做毕设为什么昆虫识别公开数据集毕设用得最多的是 IP102它有 7 万多张图、102 个类别覆盖水稻、玉米、棉花等多种作物害虫。但我不建议直接把 102 类全盘拿来训练。原因一是类别间样本极不均衡不少类只有一两百张训出来 mAP 上不去原因二是全量训练要跑很久毕设时间经不起反复试错。正确做法是按题目场景挑 5 到 10 个类。题目写水稻害虫就挑稻飞虱、二化螟、稻纵卷叶螟这一档题目写茶园害虫就挑茶尺蠖、茶小绿叶蝉、茶蚜。只保留这些类的图片重新划分训练集和验证集。这样训练时间压缩到几十分钟到两小时类别不均衡问题变小答辩时还能清楚解释“系统定位是某种作物场景”。这里有一个大部分人容易忽略的事常见的 IP102 版本是分类目录结构按文件夹放图不直接带检测框。你要做的是识别加计数必须要有框标注。所以要么从 IP102 里挑类后自己补标注要么直接找带框标注的昆虫检测数据集。自己标注时每个类最好保证 150 张图以上少于这个量模型基本学不稳。3.2 VOC 转 YOLO 格式转换脚本与四个边界坑把标注统一成 YOLO 需要的格式是数据准备里最机械也最容易错的一步。比如用 LabelImg 标注默认输出 VOC 格式 XML需要转成每张图一个 txt、每行一个框。转换脚本常见写法如下import xml.etree.ElementTree as ET import os # 类别映射表顺序必须与训练用 data.yaml 的 names 完全一致从 0 开始 CLASSES [planthopper, stem_borer, leaf_roller] def voc_to_yolo(xml_path, output_dir): tree ET.parse(xml_path) root tree.getroot() img_w int(root.find(size/width).text) img_h int(root.find(size/height).text) lines [] for obj in root.findall(object): name obj.find(name).text if name not in CLASSES: continue cls_id CLASSES.index(name) box obj.find(bndbox) x1 float(box.find(xmin).text) y1 float(box.find(ymin).text) x2 float(box.find(xmax).text) y2 float(box.find(ymax).text) # YOLO 格式归一化中心点坐标和宽高 x_center (x1 x2) / 2 / img_w y_center (y1 y2) / 2 / img_h w (x2 - x1) / img_w h (y2 - y1) / img_h # 边界保护防止标注越界导致训练出现 NaN 损失 x_center min(max(x_center, 0.0), 1.0) y_center min(max(y_center, 0.0), 1.0) w min(max(w, 0.0), 1.0) h min(max(h, 0.0), 1.0) lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) if lines: out_path os.path.join(output_dir, os.path.splitext(os.path.basename(xml_path))[0] .txt) with open(out_path, w) as f: f.write(\n.join(lines))这里有四个边界坑挨个说。第一是尺寸没转类型size/width解析出来是字符串不转 int 整个归一化全变 0。第二是类别名大小写不统一aphid和Aphid会被当成两个类转之前先统一。第三是框越界手标时 xmax 比图片宽还大必须 clip 到 0 到 1不处理轻则警告、重则训练出 NaN。第四是过小的框虫子在图里只有三五个像素时归一化宽高可能小于 0.01这些框基本学不到特征建议直接过滤掉。3.3 划分与增强小样本类别怎么喂给模型转完标注目录结构按 YOLO 惯例摆datasets/ images/ train/ val/ labels/ train/ val/划分比例我一般按 8:2数据量小可以到 9:1但 val 至少留 50 张以上否则验证集指标波动太大没法判断模型是否收敛。移动文件时注意同名图片和 txt 必须一起走很多人只拷了图片没拷 labels训练时全量标注缺失报错信息又很隐晦。增强方面YOLOv8 默认开 Mosaic、HSV 扰动和随机翻转常规够用。如果某个类只有一两百张可以做离线增强旋转 90 度、调亮度、随机裁剪翻倍后再喂给模型。注意离线增强后的图片必须重新跑一遍标注变换旋转图片的同时要旋转标注框只转图不转框是最常见的返工现场。4. 训练到导出YOLOv8 最小可复现流程4.1 环境安装与目录规划一个干净的 YOLO 项目怎么摆训练环境用 conda 新建最省事Python 选 3.10 或 3.11PyTorch 按显卡驱动装。常见做法是conda create -n insect python3.11 -y conda activate insect pip install ultralytics opencv-python pandasultralytics自带 YOLOv8 和命令行工具不需要另外装 darknet 或老版 yolov5。没有 N 卡也能用 CPU 跑只是训练慢这时把模型固定成yolov8n最小版本、epochs 降到 50先把流程跑通再放大。项目目录按下面这样摆后面写论文、补实验记录都方便insect_project/ data.yaml datasets/ images/... labels/... runs/ # 训练结果和权重默认输出到这里 scripts/ # 转换、推理脚本 weights/ # 导出和备份的模型data.yaml 里的路径建议直接写成绝对路径换机器时只改这一个文件你要是拿到的项目包路径是别人电脑上的训练第一句报找不到数据集先查 yaml别急着重装环境。4.2 训练命令与参数epochs、imgsz、batch 怎么定数据就位后训练命令一行就能跑cd insect_project yolo detect train \ modelyolov8n.pt \ datadatasets/insect.yaml \ epochs100 \ imgsz640 \ batch16 \ patience20 \ cacheTrue \ projectruns \ nameinsect_v8n配套的datasets/insect.yaml长这样path: ../datasets train: images/train val: images/val names: 0: planthopper 1: stem_borer 2: leaf_rollernames的顺序和 3.2 节CLASSES的顺序必须严格一致这是后面最容易踩的坑。常用参数怎么调直接看表参数推荐值什么时候改modelyolov8n.pt数据多、目标大时可换 yolov8s.ptepochs100数据量小或时间紧降到 80imgsz640小目标多且显存够提到 960 或 1280batch168G 显存降到 8CPU 训练降到 4patience20早停轮数时间紧可以降到 10cacheTrue内存小于 16G 改 Falsemodelyolov8n.pt表示用 COCO 预训练权重做迁移学习比随机初始化收敛快得多cacheTrue会把图片缓存进内存第一个 epoch 前多等几分钟但之后每个 epoch 读取速度大幅提升。训练时定期看runs/insect_v8n/results.csv如果 loss 出现 NaN先检查标注是否越界或学习率是否异常不要盲目调参重训。best.pt是验证集上指标最好的权重last.pt只是断点续传用。4.3 验证与导出mAP 之外还要看哪些指标训练结束不要急着写论文先在验证集上过一遍yolo detect val modelruns/insect_v8n/weights/best.pt datadatasets/insect.yaml imgsz640除了总 mAP50一定要逐类看召回率。昆虫检测最容易出现的情况是总体 mAP50 有 0.85某类召回率只有 0.5说明这个类大量漏检。漏检原因两类样本太少或目标体积太小。样本少就补数据目标小就把imgsz提上去顺带检查一下验证集图片是否和训练集来自同一分布。验证没问题后导出部署格式。网页演示用 PyTorch 权重也可以想快一点就导出 ONNXfrom ultralytics import YOLO model YOLO(runs/insect_v8n/weights/best.pt) model.export(formatonnx, imgsz640, halfTrue)halfTrue把权重转半精度显存占用减半但需要显卡支持 FP16。注意导出imgsz必须和训练一致不然推理时会重新缩放检测效果看起来“变差了”其实是导出的输入尺寸没对上。5. 避坑与排查昆虫识别毕设最容易翻车的 5 处5.1 训练到一半显存爆掉现象训练跑第一个 epoch 就报CUDA out of memory或者十几个 epoch 后中断日志最后一行是 RuntimeError。原因主要有三个batch 设大、TensorBoard 占用显存、cacheTrue先把内存吃满导致系统转用交换分区变慢。解决时先调batch8或4关掉浏览器里的 TensorBoard 页面再不够就把imgsz降成 512。6G 以下显存的卡直接坚持用yolov8n不要试yolov8s。另外混合精度在个别老显卡上有兼容问题训练日志如果显示 loss 不断跳变但指标不动可以给训练命令加ampFalse关掉自动混合精度再试。5.2 计数结果比真实数量多一倍现象一张图肉眼能数 12 只虫代码统计出 24 只输出框叠在同一只虫身上。原因通常是 NMS 阈值太宽松同一目标输出了多个重叠框或者置信度阈值设太低叶片边缘和昆虫触角被误检。解决方法是推理时把 NMS 阈值调到 0.4 到 0.45计数函数里把置信度阈值从 0.25 提到 0.35。如果偏差稳定在两倍左右还要检查是否同一个虫子被预测成两个类——NMS 按类别单独抑制两个类的高分框会同时保留。可以看输出框里是否有大量同位置不同类有的话在训练数据里查这两个类是不是混标了。5.3 mAP 很高但演示照片一个都测不出来现象验证集 mAP50 有 0.9实验表都填好了拿手机拍的虫子照片一张都测不出。原因大概率是训练数据和演示图片分布不一致光线、角度、背景差异太大另一个常见原因是演示图片分辨率太高模型内部等比缩放到 640 后虫子只剩十几个像素。解决方法是推理时把imgsz提到 960 或 1280并在训练集里补几张演示场景的图片。桌面演示时注意4000x3000 的大图直接上传小目标会被严重压缩稳妥做法是推理前先做目标区域裁剪或者接受推理变慢以换取准确率。演示机上没有显卡时宁可等两三秒出准确结果也比秒出但在乱框要强。5.4 路径含中文或空格读取不到数据集现象训练命令执行后报Cant find dataset但打开路径文件都在。原因多数是 Windows 下项目路径或图片文件名带中文和空格Ultralytics 某些组件对中文路径兼容不好还有一种情况是datasets路径大小写不一致。解决方法是项目根目录和数据集目录全用英文小写不要带空格。zip 包解压出来的文件名如果是“图像”或“数据集 最终版”统一改成images、labels。这一条能省掉大量看似玄学的报错也是我拿到任何代码包后第一件会做的事。5.5 类别 id 偏移导致训练 loss 异常现象训练能启动但 loss 一开始就很大第一轮 mAP 几乎为 0预测类别和标签完全对不上。原因几乎都是转换脚本里的CLASSES顺序和训练data.yaml的names顺序不一致整体错一位。这类问题看数值很难发现必须可视化检查。转完标注后随便抽一张验证图用下面代码推理并保存预测图肉眼看框和类别文字是否正常from ultralytics import YOLO model YOLO(yolov8n.pt) # 加载默认模型用于可视化测试 model.predict(sourcedatasets/images/val, saveTrue, exist_okTrue)如果框都在但类别文字混乱优先检查两个文件的类别顺序如果框完全错位才考虑训练数据和模型输出的坐标体系问题。6. 最后一公里把识别计数做成能答辩的展示系统6.1 用 Flask 包一个最简接口答辩现场要演示识别和计数一个 Flask 接口加上传图片的页面就够。模型加载放在全局避免每个请求重新读权重from flask import Flask, request, jsonify from ultralytics import YOLO import cv2 app Flask(__name__) model YOLO(runs/insect_v8n/weights/best.pt) app.route(/predict, methods[POST]) def predict(): path request.json[path] img cv2.imread(path) results model.predict(img, conf0.30, imgsz640) boxes results[0].boxes counter count_insects(boxes.conf, boxes.cls, results[0].names, conf_threshold0.30) return jsonify(counter)这个接口把conf显式设为 0.30就是 2.3 节说的静态计数推荐区间。计数函数复用之前定义的那个保证本地脚本和网页接口的口径一致不会本地数 12 个、网页数 20 个。6.2 演示验证的两条经验演示环节最怕现场找图结果检测效果差。我的习惯是准备三到五张验证集里效果好的图片放在独立目录现场轮着传。这不是造假是用已验证过的输入给评委展示系统稳定性。同时准备一张有代表性的失败图主动讲“这个场景下哪些原因导致漏检”远比被老师问到尴尬再解释要好。如果时间充裕可以加一个视频输入版本用 ByteTrack 做跨帧去重把“数目统计”升级成“虫口数量监测”。论文里要把口径写清楚单帧检测计数是基础指标视频追踪去重是扩展指标。我之前做过一个教训是计数只按帧累加一只停着不动的虫被算了 30 次老师一眼就看出来问题。改成只统计“新出现的目标 ID”后这个数字才真正可用。希望这些选型、参数和踩坑经验能帮你在做昆虫识别和数目统计毕设时少走弯路。本文还有配套的精品资源点击获取