多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

YOLOv8机场跑道FOD检测毕设实战:从数据集到部署全流程解析

YOLOv8机场跑道FOD检测毕设实战:从数据集到部署全流程解析 简介一套基于YOLOv8的机场跑道FOD异物监测系统面向计算机、人工智能等专业的在校学生与开发者适合用作毕业设计、课程设计或项目初期演示也适合目标检测入门者进阶学习。资源包共计九十七个文件主体为七十个Python脚本覆盖模型训练、推理计算与可视化页面另含十二个pyc编译文件、四个模型权重和若干XML、txt说明压缩包整体仅约24.21MB目录结构清晰可快速定位各功能模块。目前已有125人学习下载。项目提供完整源码、训练数据、可视化界面与部署说明可直接生成核心指标曲线图、混淆矩阵、F1分数曲线、精确率-召回率曲线、验证集预测结果及标签分布图同时还附带演示视频与README运行流程均已测试通过拿来即可使用也可基于已有代码进一步扩展其他检测功能充分支撑答辩展示与二次开发。1. FOD检测毕设怎么做一个能直接跑通的YOLOv8落地方案机场跑道异物FOD检测不是什么新鲜概念但绝大多数毕设和课设都卡在同一个地方——数据没有、代码拼不齐、训练起来显卡不够用。这份资源包的定位很直接把YOLOv8检测模型、可视化界面、完整数据集、部署教程打包到一起解压之后跟着教程走目标是让一个稍懂Python的人能在两天内跑出可演示的结果。它解决的不是「从零写网络」的问题而是「把检测系统端到端搭起来」的问题。适合正在做毕业设计、课程设计或者想快速验证目标检测技术栈的人不适合想彻底搞懂YOLOv8内部原理的算法研究者。下面我把拆包后的核心内容、训练参数和排错经验逐一展开。2. 数据集与预处理把异物样本转成YOLOv8能吃的txt格式2.1 从下载包里先看清数据长什么样解压后先别急着跑训练。第一件事是打开数据集目录确认标注格式。大多数FOD相关数据集原始标注是VOC的xml格式或者COCO的json格式YOLOv8训练时需要的是每张图片对应一个同名txt文件每行内容为class_id cx cy w h坐标全部归一化到0到1之间。如果压缩包里的数据集已经是YOLO格式直接跳到2.3如果是xml需要先做一次转换。转换脚本是这类资源里最常见的配套工具。核心逻辑就是解析xml里的object节点取出边界框坐标再除以图片宽高做归一化。下面这段代码可以直接用于批量转换import os import xml.etree.ElementTree as ET from PIL import Image def xml_to_yolo(xml_path, img_dir, out_dir, classes): tree ET.parse(xml_path) root tree.getroot() img_file root.find(filename).text img_path os.path.join(img_dir, img_file) with Image.open(img_path) as img: w, h img.size out_txt os.path.join(out_dir, os.path.splitext(img_file)[0] .txt) with open(out_txt, w) as f: for obj in root.iter(object): cls_name obj.find(name).text if cls_name not in classes: continue cls_id classes.index(cls_name) box obj.find(bndbox) x_min float(box.find(xmin).text) y_min float(box.find(ymin).text) x_max float(box.find(xmax).text) y_max float(box.find(ymax).text) cx (x_min x_max) / 2 / w cy (y_min y_max) / 2 / h bw (x_max - x_min) / w bh (y_max - y_min) / h f.write(f{cls_id} {cx:.6f} {cy:.6f} {bw:.6f} {bh:.6f}\n) # 使用示例 classes [bolt, metal_fragment, plastic, rubber] xml_to_yolo(data/annotations/train.xml, data/images/train, data/labels/train, classes)这段代码里有两个容易出错的地方。一是filename节点读到的是不带路径的文件名拼接图片路径时要保证img_dir写法正确否则Image.open报文件不存在。二是classes列表的排序必须固定训练和推理阶段沿用同一个列表一旦换顺序之前生成的txt标注就全错位了。建议在转换之前把类别列表写进配置文件之后训练和验证都从该配置读取避免手动维护两份列表带来不一致。2.2 训练集划分与检查脚本转换完成之后需要把标注随机划分为train和val两部分。YOLOv8本身在train命令里支持传data.yaml指定训练和验证集路径所以划分的逻辑就是把图片和txt文件名按比例随机分配。常见做法是用8:2的比例划分然后单独生成两个文件清单。也可以用sklearn的train_test_split但对于文件操作一行shell命令配合shuf也能做到。我一般会额外写一个数据完整性检查脚本统计每个标签文件的类别分布和标注框数量。这一步是为了防止「某个类别只有三五个样本」这种隐藏问题。FOD检测的特殊性在于异物类别极度不平衡——金属碎片可能有两千条标注而塑料袋可能只有五条训练出来塑料类几乎不可用。先跑一遍统计心里有底import os from collections import Counter label_dir data/labels/train counts Counter() for fname in os.listdir(label_dir): if not fname.endswith(.txt): continue with open(os.path.join(label_dir, fname)) as f: for line in f: cls_id int(line.split()[0]) counts[cls_id] 1 print(counts)输出结果如果发现某类标注数少于20就要考虑扩充数据或合并类别。FOD场景里很多毕设项目最终只有3到4类异物金属件、塑料片、橡胶条、石子类别一多、样本不够模型几乎必翻车。这个检查脚本虽然简单但能避免训练完才发现的「类别玄学」问题——不是模型不行是数据不行。2.3 路径配置与data.yaml写法YOLOv8训练前需要准备好data.yaml它负责告诉训练器哪里找图片、哪里有标签、共几个类别。里面的路径建议直接写绝对路径虽然YOLOv8也支持相对路径但很多新手在根目录或工作区之间切换时相对路径会悄悄跑偏导致报错No labels found。这是最容易被忽略的一类问题。# data.yaml path: /home/user/fod_data train: images/train val: images/val nc: 4 names: [bolt, metal_fragment, plastic, rubber]path字段是数据集根目录train和val都是相对path的子目录。nc必须和names里的类别数一致。这里有一个值得强调的细节yaml文件里不要出现中文路径也不要出现带空格或中文的文件夹名。YOLO系列对路径里包含中文字符或空格的支持一直不太稳定训练阶段运气好能过但导出和推理阶段常出怪问题。把所有目录统一改成英文小写加下划线能省掉很多血泪经验。3. 训练参数与迁移学习用小显存跑通识别模型的四组关键配置3.1 为什么非要从预训练权重开始YOLOv8训练时有--weights参数常见选择是yolov8n.pt或yolov8s.pt。几兆到几十兆的预训练权重在COCO上已经学好了通用的纹理、边缘和形状特征。FOD检测里的金属、塑料、橡胶虽然在COCO里不一定有直接对应类别但底层特征高光、轮廓、表面纹理是通用的。从预训练权重开始微调相当于站在一个已经会「看」的模型上只学「认异物」100个epoch就能达到不错效果从头训练则大概率在验证集上挣扎很久。毕设场景和工程落地的区别在于前者追求稳定出图、演示效果好后者追求极致精度。所以资源包里的训练配置通常是拿yolov8n或yolov8s起步显存占用少推理快720p画面跑个实时检测也够用。如果你有两张以上显卡或者显存超过12G可以往yolov8m上试但最终收益边际递减数据量不够时反而更容易过拟合。3.2 训练命令与关键参数说明以下命令是典型的FOD训练入口可以直接在终端跑yolo detect train \ --model yolov8s.pt \ --data data.yaml \ --epochs 150 \ --batch 16 \ --imgsz 640 \ --device 0 \ --patience 20 \ --workers 4 \ --project runs/fod \ --name exp1参数含义逐个说清。--model指定基础权重可以是预训练权重文件也可以是yolov8s.yaml纯结构定义不加载预训练不建议。--epochs设150配合--patience 20表示连续20个epoch验证集mAP没有提升就提前停止对于毕设数据集通常70到100轮就能收敛。--batch在8G显存的卡上建议先试16如果报OOM显存溢出降到8。--imgsz是输入分辨率640是精度和速度的平衡点FOD很多是小目标用896能提升小目标召回率但显存占用翻倍还多。--device填0表示用第一张显卡没有显卡就填cpu但训练速度会慢到怀疑人生建议直接租个GPU跑。训练结束后控制台会输出results.csv包含每一轮的metrics/mAP50(B)、metrics/mAP50-95(B)等指标。不要只盯最后的数字要看曲线的走势——如果mAP50在训练集上持续走高、验证集却在某个点后走平甚至下降说明过拟合了应该把epoch数砍半或调大--patience。FOD的数据量一般在几千张级别150轮通常足够收敛。3.3 数据增强参数用翻转和Mosaic稳住小样本YOLOv8在训练时默认开启Mosaic、随机翻转、色彩抖动等数据增强。对小样本的FOD项目来说增强是救命的。特别是Mosaic——把四张图拼接成一张训练图等于变相扩大了每张图的上下文信息也能让小目标在训练里出现得更密集。但如果FOD物体本身很小Mosaic可能让目标缩得更小、更难学。遇到这种情况可以在训练命令里显式降低增强强度yolo detect train \ --model yolov8s.pt \ --data data.yaml \ --epochs 150 \ --batch 16 \ --imgsz 640 \ --device 0 \ --mosaic 0.5 \ --hsv_h 0.015 \ --hsv_s 0.7 \ --hsv_v 0.4--mosaic 0.5表示只有一半的batch会应用Mosaic增强默认值是1.0。如果你的FOD数据集样本较少建议先从0.8或1.0跑一次看看验证集曲线如果验证指标波动大、训练不稳定再调低到0.5。hsv系列参数控制色相、饱和度、明度的随机扰动范围机场跑道那种灰色水泥地面不需要太多的色彩扰动否则模型会把颜色偏移当成有效特征。我自己做这个项目时曾经把饱和度扰动拉到0.9结果模型在灰色地板上疯狂误检深色阴影这就是增强参数没根据场景调导致的翻车。3.4 训练过程监控与断点续训训练跑起来之后用tensorboard --logdir runs/fod就能在浏览器里实时看loss曲线、学习率变化和验证集指标。YOLOv8会把日志写到runs/fod/exp1/目录下。如果中途机器断电或者显存崩了不用从头再来用断点续训yolo detect train \ --model runs/fod/exp1/weights/last.pt \ --data data.yaml \ --resume \ --epochs 150--resume会自动读取训练状态从最近的epoch继续。这里有一个细节--model参数要指向last.pt而不是best.pt。best.pt只是指标最好的快照不能当作断点状态来恢复优化器和学习率调度的位置。很多人在这儿栽跟头以为用best续训更好结果学习率被重置loss曲线直接放飞。4. 部署与可视化界面从权重到可点击的实时检测Demo4.1 推理脚本的骨架加载权重、读画面、画框训练完的权重在runs/fod/exp1/weights/best.pt。部署阶段要做的不是写训练循环而是写推理服务。最简单的方式是直接用YOLOv8官方提供的Python接口from ultralytics import YOLO import cv2 model YOLO(runs/fod/exp1/weights/best.pt) cap cv2.VideoCapture(0) # 0为摄像头编号Rtsp流可直接填URL cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720) while True: ret, frame cap.read() if not ret: break results model.predict(frame, conf0.25, imgsz640, verboseFalse) annotated results[0].plot() cv2.imshow(FOD Detection, annotated) if cv2.waitKey(1) 0xFF ord(q): break cap.release() cv2.destroyAllWindows()这段代码是界面联调之前最核心的功能雏形。conf0.25是置信度阈值FOD场景建议在0.2到0.4之间调。阈值调低了会看到很多误检框调高了漏检严重——如果跑道上一个拇指大的金属片置信度老在0.2附近徘徊那说明训练数据里类似样本太少不是阈值的问题。verboseFalse关掉控制台逐帧打印不然每秒输出几十行推理日志终端刷得飞起也没人看。4.2 可视化界面工程化线程里跑模型主线程画界面很多毕设要求「有个界面」于是Tkinter或PyQt5成为标配。最常见的坑是直接在UI主线程里跑检测循环图片还没推理完界面就卡住不动了甚至battery的CPU打满退出按钮也失灵。解决办法是把检测放进独立线程主线程只负责接收检测后的帧并刷新画面。import threading import queue import cv2 from ultralytics import YOLO class FODDetector: def __init__(self, model_path, conf0.25): self.model YOLO(model_path) self.conf conf self.frame_queue queue.Queue(maxsize1) self.result_queue queue.Queue(maxsize1) self.running True def start(self): self.t threading.Thread(targetself._loop, daemonTrue) self.t.start() def _loop(self): while self.running: frame self.frame_queue.get() results self.model.predict(frame, confself.conf, imgsz640, verboseFalse) annotated results[0].plot() if self.result_queue.full(): try: self.result_queue.get_nowait() except queue.Empty: pass self.result_queue.put(annotated) def stop(self): self.running Falseframe_queue和result_queue做解耦视频流的生产速度远快于模型推理速度所以队列长度都设为1放不下就丢弃旧帧只保留最新画面。这样UI线程每30毫秒从result_queue取一帧刷新模型推理再慢界面也不会卡只是检测帧率会下降。这是工程上的常见做法也是资源包自带的界面代码里最值得参考的部分。4.3 批量测试与结果落盘给答辩准备一张效果表毕设答辩需要的数据不外乎精确率、召回率、平均精度这些通过yolo val一键计算yolo detect val \ --model runs/fod/exp1/weights/best.pt \ --data data.yaml \ --batch 8 \ --imgsz 640 \ --save_json \ --save_txt \ --save_conf加--save_txt会把每张图的检测结果存成txt--save_conf额外保存置信度。跑完后算法自动输出各类别的AP、mAP50、mAP50-95等指标这些数字可以直接放进论文或答辩PPT。如果你想对一段测试视频逐帧统计漏检率可以参考上面的线程模型写一个小脚本把所有检测帧置信度记录下来再比对标注。这个表格比一句「模型效果不错」有说服力得多。5. 避坑排查与效果验证五条血泪记录和一组可复用的验证方法5.1 训练时报CUDA out of memory最常见的报错没有之一。现象是训练跑了几十个step直接崩掉提示显存不足。原因除了powermap太大或batch过大还有可能是你同时挂着其他程序占显存比如浏览器、桌面录屏或另外一个jupyter kernel。解决思路分两步先关掉所有无关的GPU应用再把batch降到8imgsz从640降到512。如果还是OOM最后手段是把device改成cpu——但纯CPU训练速度极慢150个epoch可能要跑一天多不建议。5.2 验证集mAP一直卡在0.5上不去现象是训练loss在降mAP50却纹丝不动。原因大概率是标注框太小比如FOD目标整张图只有8x8像素YOLO在640分辨率下下采样到20x20的特征图上这个目标几乎只有一个点根本学不到特征。解决方法是提高输入分辨率到896同时把--anchor相关配置检查一遍YOLOv8自动学习anchor但小目标仍受限于特征图网格。另一个对策是检查标注是否有边界框中心坐标偏移——用2.2节的统计脚本核对一下如果大量标注框中心点集中在图像边缘说明xml转txt时的坐标算错了。5.3 推理时检测框在抖动但置信度很高这种问题在FOD视频检测里特别明显同一个物体上一帧框很稳下一帧框突然跳出去一段距离然后又跳回来。原因是模型对背景纹理的响应太强物体边缘模糊时模型会抓住周围的地面裂缝或阴影作为依据。解决方法是先调高--conf到0.35或0.4把置信度低的边缘检测滤掉如果还想更稳可以引入后处理对连续5帧的同类别检测框做平均值平滑。这里有一个简单的时序滤波器思路记录每个目标的检测框中心如果当前帧和上一帧的距离变化超过整张图宽度的15%就判定为误检丢弃这一帧的结果。5.4 界面打开后摄像头画面黑屏现象是程序不报错但界面上什么都没有。原因通常是摄像头被别的程序占用比如本地视频会议软件或者opencv读取摄像头的后端不支持你笔记本的摄像头分辨率。解决时先单独跑一遍只读摄像头的测试脚本确认摄像头在本机可用然后在初始化代码里加cv2.CAP_DSHOWcap cv2.VideoCapture(0, cv2.CAP_DSHOW) cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)CAP_DSHOW是Windows平台下更稳定的一种后端用它之后很多摄像头打不开的问题直接消失。监听视频流时也一样如果RTSP流没问题但画面卡顿先把分辨率设到640并降低帧率排查网络带宽和延时ffprobe -v error -select_streams v:0 -show_entries streamwidth,height,avg_frame_rate -of defaultnoprint_wrappers1 rtsp://your_camera_urlffprobe输出的分辨率和帧率如果远超你的解码能力就在opencv里手动缩放后再喂给模型。摄像头端的坑基本都是环境层面的跟模型本身没关系。5.5 换机器后权重加载报RuntimeError: re-initialization或维度不匹配这个坑通常出现在你在一台电脑上训练完把best.pt拷到另一台电脑推理时。原因是本地安装的YOLOv8版本和你训练时不一致版本差异导致权重结构里某些层对不上。解决方法是把权重往上转换或在目标机上安装和训练环境完全相同的ultralytics版本。更稳妥的办法是导出为ONNX格式ONNX不依赖Python环境yolo export modelruns/fod/exp1/weights/best.pt formatonnx opset12导出之后用onnxruntime推理基本能做到「环境随便换、权重不走样」。唯一的代价是ONNX模型少了训练时的各种增强逻辑推理结果会和原权重有一些细微差异但置信度和框位置基本一致。从那以后我每次部署模型到别人的机器上都强制走一遍ONNX导出流程再也没被版本问题坑过。5.6 效果验证的最后一公里保存一次带指标的检测图除了跑val拿到数值指标还建议对视频和图片各保存一批带检测框的标注结果挑3到5张有典型代表性的放进论文或答辩PPT比如一张小目标命中、一张多目标同时检出、一张有遮挡情况。这些图比任何文字都有说服力。再配合yolo val输出的混淆矩阵和PR曲线完整性就够了。整个项目拆下来的感受是这个资源最实用的是把数据格式、训练流程和界面部署已经串好了你需要做的只是换数据、调参数、解决自己机器上特有的一两个环境问题。如果你卡在某个环节超过半小时回去看资源包自带教程里的环境清单确认torch、torchvision、ultralytics三个包的版本是否对应——这个组合能解决至少一半的玄学报错。希望帮到你。本文还有配套的精品资源点击获取
返回列表