ARTICLE DETAIL

资讯详情

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

基于YOLOv8的昆虫识别与数目统计毕业设计全流程实战

基于YOLOv8的昆虫识别与数目统计毕业设计全流程实战 简介这是一套面向高校大四学生及课程设计、毕业设计场景的昆虫识别与数目统计项目资源。项目以计算机视觉技术为核心从数据准备、模型训练到界面展示形成完整闭环适合需要快速搭建毕设原型或进行相关课题研究的开发者参考。压缩包共164个文件约14.59MB其中包含97张昆虫图像样本、23个Python脚本、13个npy数据文件、10个xml标注文件、9张png图片、3个训练好的model模型、3个csv表格数据、1个ui界面文件及说明文档等目录结构较为完整可支撑从数据读取、模型推理到结果统计的整套流程。该资源已有140人学习下载具有一定的参考热度。读者可从中获得可运行的代码框架、已标注的数据集与模型文件以及界面设计思路能够帮助理解目标检测与计数任务的实际实现方式减少重复开发成本。1. 昆虫识别与数目统计的毕业设计题实质是两件事把“昆虫识别和数目统计”丢给做过目标检测的人第一反应是“这不就是YOLO出框、数框嘛”。真做起来会发现识别是识别统计是统计中间隔着一条把检测框变成业务数字的鸿沟。识别要解决昆虫类间相似、类内变态期差异、小目标占比高这些视觉问题数目统计要解决的则是同一只虫在视频里出现多帧、群聚重叠、目标遮挡之后的去重与计数策略。这个题目作为大四毕业设计常见做法是“检测模型 计数后处理”两条线并行用目标检测框架训一个能区分若干昆虫类别的模型再在输出层之外单独设计数目统计算法。本文按这个思路拆开讲覆盖选型、数据、训练、计数实现和答辩部署给出一套能直接落地的技术方案。2. 技术选型昆虫识别用哪类检测算法YOLOv8 为什么是底线2.1 检测模型对比两阶段、单阶段与端到端方案的取舍昆虫识别属于典型的目标检测任务候选方案无非三类以 Faster R-CNN 为代表的两阶段检测器以 YOLO 系列为代表的单阶段检测器以及 RT-DETR、DINO 这类基于 Transformer 的端到端检测器。两阶段检测器精度上限高但推理速度慢训练时需要单独管理 RPN 和检测头对课设和毕设的周期来说性价比低。RT-DETR 省去了锚框和 NMS在公开数据集上表现亮眼但收敛依赖大数据量如果昆虫数据集只有几千张训练不稳定是常态。YOLO 系列在精度和速度之间最均衡v8 版本把 anchor-free 检测头、C2f 结构和多种数据增强策略集成在 Ultralytics 框架里一个配置文件加几行命令就能完成训练、验证和导出。对于需要现场演示和答辩跑 demo 的场景训练快、推理快、生态成熟这三点比极致精度更重要。我一般会建议在 YOLOv8n 或 YOLOv8s 之间选。昆虫数据集通常不大几百到两三千张v8n 参数量小不容易过拟合CPU 上也能勉强推理v8s 精度更好适合有一张普通显卡的环境。如果后续想做性能对比实验可以再跑一版 v8l 或 RT-DETR 作为对照组写论文时多一张消融表格。但底线是 YOLOv8 及其配置管理方式不要从零实现检测网络毕业设计的时间经不起这样消耗。2.2 环境搭建与预训练权重的作用环境搭建用 Ultralytics 官方包即可Python 3.9 以上版本都兼容。核心安装命令如下pip install ultralytics onnxruntime安装完成后先做一次最小验证用预训练权重跑通推理链路yolo predict modelyolov8n.pt sourcehttps://ultralytics.com/images/bus.jpg这一步的用途不是训练而是确认 GPU 或 CPU 推理环境可用同时验证 CUDA 版本与 PyTorch 是否匹配。如果predict能正常输出标注图片说明环境没问题可以进入数据阶段。这里的yolov8n.pt是 COCO 预训练权重迁移学习的意义在于 COCO 上的卷积特征对昆虫的纹理、边缘、颜色有泛化迁移能力尤其是背景类和昆虫形态差异较大的情况下预训练权重能显著缩短收敛时间。需要注意COCO 中没有太多细粒度昆虫类别不能指望预训练直接给出好的昆虫特征它只是提供一个初始化起点最终结果仍然依赖专门的数据。2.3 分类粒度怎么定物种级还是形态级昆虫识别的类别定义是数据阶段的决策但必须在选型时同步想清楚。常见做法有两种按物种分类例如“蝶、蛾、蜂、蝇”每组内部仍存在大量近似外观按生态功能或拍摄场景分类例如“传粉昆虫、害虫、中性昆虫”。从模型角度类别越细类间距离越小误检率越高从统计角度类别定义直接影响后续数目统计的维度——是统计总虫数还是分种类统计。毕设题目里“昆虫识别”没有限定粒度我会把类别数量控制在 5 到 15 类每类样本 150 张以上。类太少体现不出识别难度类太多数据采集工作量会压垮项目进度。这个决策要在论文里给出理由答辩时能解释“为什么选这 8 类而不是按科属全部展开”本身就是加分项。3. 昆虫数据集的采集、清洗与标注别急着跑训练3.1 样本来源与类别不均衡处理昆虫没有现成的大规模公开数据集可以直接对齐到自定义类别常见做法是自己拍摄、从开放图库采集、或借助网络爬虫获取图像。无论来源如何第一步是盘点类别分布。我一般会先把所有图像文件按类别放到独立文件夹写一个统计脚本输出每类图片张数优先淘汰样本不足的类别。若某类样本特别少可以用水平翻转、旋转、亮度扰动做离线增强但不会单纯复制粘贴图片充数——那种做法只会增加过拟合风险。类别不均衡是昆虫数据里的常态。比如“苍蝇”样本容易采集“寄生蜂”样本可能很难拍满 200 张。处理方法上训练时开启 Ultralytics 的fraction参数控制每类参与训练的比例或者在数据配置里对少样本类别提高重复采样次数。更直接的做法是重新定义分类粒度把难以凑齐样本的类别合并为“其他昆虫”。不要小看这个合并操作它对最终精度的正面影响往往比调模型参数更大。3.2 图像清洗脚本过滤损坏文件和重复样本采集到的图像里总会有下载失败的空文件、截断的 JPEG、以及大量重复图片。这些脏数据进入训练集后轻则浪费训练时间重则导致训练中断。下面这段脚本可以过滤掉无法被 PIL 解码的图像from PIL import Image import os import hashlib img_dir raw_images valid_dir cleaned_images os.makedirs(valid_dir, exist_okTrue) seen_hashes set() for root, _, files in os.walk(img_dir): for fname in files: path os.path.join(root, fname) try: with Image.open(path) as img: img.verify() # 验证文件完整性 with open(path, rb) as f: file_hash hashlib.md5(f.read()).hexdigest() if file_hash in seen_hashes: print(f丢弃重复图片: {path}) continue seen_hashes.add(file_hash) # 重新打开一次verify() 之后需要重新加载才能读取尺寸 with Image.open(path) as img: img.load() # 统一转换为 RGB避免 PNG 带透明通道影响后续标注 rgb_img img.convert(RGB) rgb_img.save(os.path.join(valid_dir, fname)) except Exception as e: print(f过滤损坏文件: {path}, 原因: {e})这段代码做了三件事用verify()检查图像文件是否完整且能解析通过计算 MD5 哈希去掉内容完全相同的重复图片统一转换为 RGB 格式。参数说明img.verify()只校验文件结构不加载像素数据所以后面必须重新Image.open一次才能操作哈希去重对同一张图的不同分辨率副本无效如果爬虫采到同一场景不同尺寸的图还需要加上感知哈希pHash进一步去重普通毕设做完 MD5 去重就够用。3.3 标注工具选型与 VOC 转 YOLO 格式标注采用 LabelImg 或 X-AnyLabeling 均可前者轻量稳定后者支持半自动辅助标注。昆虫图像的特点是目标多、面积小一个 1080p 画面里可能有几十只虫逐只框很费时。常见做法是先标注 100 张图训练一个初版模型再用模型对剩余图片做预标注人工修正边框。这个流程能省一半以上时间。标注格式上LabelImg 默认输出 VOC XML。YOLO 训练需要的是 txt 格式每行对应一个目标内容是类别id x_center y_center width height坐标值归一化到 0 到 1。写一个转换脚本批量处理import xml.etree.ElementTree as ET import os def voc_to_yolo(xml_path, out_txt_path, class_map): 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): cls_name obj.find(name).text if cls_name not in class_map: continue cls_id class_map[cls_name] bbox obj.find(bndbox) xmin float(bbox.find(xmin).text) ymin float(bbox.find(ymin).text) xmax float(bbox.find(xmax).text) ymax float(bbox.find(ymax).text) x_center (xmin xmax) / 2 / img_w y_center (ymin ymax) / 2 / img_h width (xmax - xmin) / img_w height (ymax - ymin) / img_h lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}) with open(out_txt_path, w) as f: f.write(\n.join(lines)) class_map {butterfly: 0, bee: 1, fly: 2, beetle: 3, moth: 4} voc_to_yolo(annotations/001.xml, labels/001.txt, class_map)坐标归一化是关键因为 YOLO 在训练时会将输入图像缩放到imgsz指定尺寸归一化坐标保证缩放后目标位置依然准确。class_map字典需要和数据配置文件里的names保持一致顺序错一个训练出的模型预测类别就全乱了。3.4 小目标占比高切图策略的利弊昆虫在整张图片里往往只占几十个像素直接送进网络下采样到 640x640 后小目标特征会被压缩到几乎没有。解决小目标检测的常见做法有两种一是提高输入分辨率到 960 或 1280二是切图推理。切图把大图拆成多个 640x640 的 patch每个 patch 单独检测再汇总结果。优势是保留小目标原始尺度缺点也很明显跨 patch 的同一只虫会在拼接处被重复检测需要做 NMS 合并。毕设阶段如果训练图本身是手机拍摄的近景昆虫目标占比通常不小先用 640 分辨率训练观察 mAP 中小目标指标再决定是否切图不要一开始就上切图徒增复杂度。4. 训练与调参损失曲线、分辨率与置信度的取舍4.1 数据集配置文件与训练命令标注完成后需要写一个 YAML 文件描述数据路径和类别信息放在项目根目录下。示例如下path: /home/user/insect_project train: images/train val: images/val nc: 5 names: [butterfly, bee, fly, beetle, moth]path是项目根路径train和val是相对于根路径的训练集与验证集目录nc是类别数names顺序必须与标注脚本里的class_map一致。这里有个常见错误Windows 用户在 YAML 里写反斜杠路径Ultralytics 解析时会报路径错误统一用绝对路径的正斜杠或相对路径能省很多事。启动训练的命令yolo detect train datainsect.yaml modelyolov8n.pt epochs120 imgsz640 batch16 optimizerAdamW lr00.01 patience20参数说明modelyolov8n.pt表示加载 COCO 预训练权重做迁移学习epochs120对昆虫数据量足够再多容易过拟合imgsz640是输入分辨率如果类别里包含大量微型昆虫可以改 960但训练时间会显著增加batch16根据显存调整显存不足时报 CUDA out of memory 就把 batch 减半patience20表示 20 个 epoch 内验证集指标没有提升就提前停止。训练完成后runs/detect/train/weights/best.pt就是验证集上表现最好的权重。4.2 三个必须盯的指标与常见误读训练日志里的box_loss、cls_loss、dfl_loss要分开看。box_loss反映边框回归的收敛程度一直抖动不降通常意味着锚框质量差或目标尺度变化大调高imgsz会直接改善cls_loss降不下去说明类别特征没有学出来优先检查类别定义是否重叠比如“蛾”和“蝶”在图像上确实难分。mAP50和mAP50-95的差别更关键——前者只要求在框和真实框 IoU 超过 0.5 时算命中对昆虫识别这种任务够用后者要求更高对齐精度如果mAP50高但mAP50-95低说明模型能找到目标但边界框不准后续数目统计会吃亏因为边界框不准会直接影响跨帧去重时的 IoU 匹配。验证集上还要单独看每类别的召回率。总数统计对漏检最敏感漏了一只就是少计一只而错检最多是类别标错或误检为背景。recall 低时优先考虑降低conf_thres的默认值 0.25推理阶段改成 0.1 看看漏检目标是否被召回如果召回明显提升但误检爆炸再训练时就要增加对应负样本。4.3 训练过程的三个坑早停误判、类别不均衡、增强过度Ultralytics 自带早停机制但它在验证集 mAP 出现平台期时也可能过早停止。我一般把patience调到 20 以上避免模型还在收敛就被掐断。类别不均衡的坑则体现在训练日志的混淆矩阵里样本多的类召回率虚高样本少的类普遍偏低。此时不是继续加训练轮数而是回数据阶段补样本或合并类别。第三个坑是数据增强过度。YOLOv8 默认开启 mosaic、mixup 等增强对昆虫这种小目标密集场景mosaic 会把不同图片切块拼接小昆虫被拼接缝裁掉一半反而制造了大量难以学习的目标。若发现训练损失持续震荡考虑关闭部分增强yolo detect train datainsect.yaml modelyolov8n.pt epochs120 imgsz640 mosaic0.0 mixup0.0mosaic0.0不是彻底禁用该增强而是把概率权重设为 0。关闭后模型收敛更稳定代价是泛化能力略降适合标注质量高、背景相对一致的数据。5. 数目统计的实现从检测框到可靠计数的三步5.1 静态图像的计数直接数框的局限静态单张图片上计数最直接的方式是统计置信度超过阈值的检测框数量。这个做法在画面干净、昆虫分散时没问题一旦出现两个靠得很近的目标检测框会合并成一个大框或者 NMS 时丢掉一个框计数就偏少。另一个问题是置信度阈值的选择阈值设 0.5模型在低置信度下检出的真目标会被过滤阈值设 0.1误检框会虚增计数。正确做法是先绘制“置信度—计数”曲线找到曲线斜率突变的位置作为阈值而不是凭经验拍一个数。计算代码如下import cv2 from ultralytics import YOLO model YOLO(best.pt) image cv2.imread(test.jpg) results model.predict(image, conf0.1, iou0.45, verboseFalse) boxes results[0].boxes for thresh in [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7]: count int((boxes.conf thresh).sum()) print(fconf {thresh:.1f}: {count} 只)iou0.45控制 NMS 合并的重叠阈值值越小重叠框越容易被合并昆虫类目标距离近时这个值调低到 0.4 可以减少重复框但太小会把同一只虫的两个叠加框误判为不同目标导致漏检。建议静止场景保持 0.5 左右密集群聚场景调整为 0.4。5.2 视频跨帧计数用 IoU 匹配做个体去重毕设题目里“数目统计”如果面向视频跨帧去重就是绕不开的问题。一只昆虫在 30fps 视频里停留 5 秒会产生 150 帧检测结果直接累加逐帧计数会得到一个天文数字。常见做法是逐帧做检测然后根据相邻帧检测框的 IoU 判断是否是同一只虫当前帧某个框与上一帧某个框的 IoU 大于阈值就认为是同一个体继续使用上一次分配的 ID否则视为新个体ID 加一。简化实现如下import numpy as np def compute_iou(box1, box2): x1 max(box1[0], box2[0]) y1 max(box1[1], box2[1]) x2 min(box1[2], box2[2]) y2 min(box1[3], box2[3]) inter max(0, x2 - x1) * max(0, y2 - y1) area1 (box1[2] - box1[0]) * (box1[3] - box1[1]) area2 (box2[2] - box2[0]) * (box2[3] - box2[1]) union area1 area2 - inter return inter / union if union 0 else 0 prev_boxes [] tracking_id 0 seen_ids set() for frame_boxes in video_detections: # video_detections 是逐帧检测框列表 matched_prev_indices set() for box in frame_boxes: best_iou 0.4 best_idx -1 for idx, prev_box in enumerate(prev_boxes): if idx in matched_prev_indices: continue iou compute_iou(box, prev_box) if iou best_iou: best_iou iou best_idx idx if best_idx 0: matched_prev_indices.add(best_idx) continue # 同一只虫只延续 ID不新增计数 else: tracking_id 1 seen_ids.add(tracking_id) prev_boxes frame_boxes逻辑说明compute_iou计算两个边界框的交并比matched_prev_indices用来防止一帧内两个检测框匹配到同一个上一帧目标加入了 ID 分配机制但不实现完整跟踪器。这个简化方案对昆虫移动缓慢、帧率较高的场景效果尚可但对快速飞行的昆虫帧间位置变化大IoU 可能低于阈值导致重复计数。提升方案是结合目标中心点距离做匹配当 IoU 接近 0 但中心距离小于目标自身尺寸时也视为同一目标。若毕设要求更高的计数准确率可以集成 ByteTrack 这类轻量级多目标跟踪库效果更稳定但会引入跟踪参数调优的额外工作。5.3 按区域统计只数特定区域内的昆虫很多昆虫统计任务不是数整张图的个体而是数某个特定区域内出现的数量例如黄色粘虫板上的蓟马、培养皿里的果蝇。实现方式是对检测框中心点做多边形包含判断import cv2 def point_in_polygon(x, y, polygon): return cv2.pointPolygonTest(polygon, (x, y), False) 0 region np.array([[100, 100], [400, 100], [400, 300], [100, 300]], dtypenp.int32) count 0 for box in boxes: cx (box[0] box[2]) / 2 cy (box[1] box[3]) / 2 if point_in_polygon(cx, cy, region): count 1区域计数需要考虑边界效应中心点恰好落在区域边缘外的个体会被排除如果这些个体一半在区域内一半在外计数就有偏差。常见处理是扩大区域边界一个检测框平均尺寸的范围把边缘个体容差进来。动态区域则更复杂比如相机抖动造成的区域偏移需要引入帧间配准超出常规毕设范围选题时量力而行。6. 部署与答辩导出模型、验证误差与现场演示技巧6.1 导出 ONNX 并封装计数 API答辩现场不能依赖训练环境跑推理把模型导出为 ONNX 并使用 onnxruntime 做 CPU 推理是最稳妥的交付方式。导出命令yolo export modelbest.pt formatonnx opset12 simplifyTruesimplifyTrue会对计算图做常量折叠和冗余节点删除减少推理耗时。导出后写一个轻量 API 提供图片上传和计数返回from fastapi import FastAPI, UploadFile import cv2 import numpy as np import onnxruntime as ort app FastAPI() session ort.InferenceSession(best.onnx, providers[CPUExecutionProvider]) app.post(/count) async def count_insects(file: UploadFile): data await file.read() img cv2.imdecode(np.frombuffer(data, np.uint8), cv2.IMREAD_COLOR) # 实际代码需包含 letterbox 预处理与输出后处理 # 此处省略核心是读取 ONNX 输出 [1, 84, 8400] 的特征图 return {count: 12, classes: {bee: 7, fly: 5}}演示时可以把前端做成简单的 HTML 上传页也可以用 Gradio 写一个拖拽上传的交互界面后者代码量少、观感更好。注意 ONNX 输出的后处理与 YOLOv8 PyTorch 版本不同需要手动解码预测框、做置信度过滤和 NMS这部分建议在答辩前单独编写并测试。6.2 误差验证方法人工计数与模型计数的对比答辩评委最常问的问题之一是本设计的计数准确率是多少。合理做法是准备 30 到 50 张测试图人工逐张计数作为真值模型计数作为预测值计算平均绝对百分比误差 MAPEMAPE (1/n) * sum(|实际数 - 预测数| / 实际数) * 100%统计一张表按类别分别列出人工数、模型数、误差率。误差来源要能在答辩时说明白遮挡导致漏检、背景纹理误检、密集目标框合并。这些问题比精度数值本身更能体现工作量。6.3 加分演示技巧把检测框和计数过程可视化现场演示环节建议加载模型后用摄像头实时推理画面右上角绘制实时计数检测框用不同颜色区分类别。这里有一个小技巧推理脚本里加上annotator绘制置信度文本同时记录每秒帧数FPS把 FPS 和检测数量同时显示在画面左上角。这样评委能直观看到模型是实时运行的而不是播放预录视频。对昆虫快速移动导致的帧间重复计数问题可以现场展示 5.2 节的 IoU 去重逻辑在视频窗口中的 ID 号变化强调“同一只虫在不同帧的 ID 保持不变计数不重复增加”这一设计细节这比任何文字描述都更有说服力。本文还有配套的精品资源点击获取
返回列表