简介:本资源面向计算机视觉初学者与无人机应用开发者,提供一套开箱即用的小型固定翼无人机YOLOv8检测解决方案,解决目标检测模型训练难、数据集稀缺、部署界面缺失等实际问题。压缩包共2000个文件,含1892个YOLO格式标注txt文件(已划分train/val/test)、90个Python脚本(含PyQt检测界面、训练与推理逻辑)、4个配置yaml文件(含data.yaml明确标注nc:1与类别名FixedWing-Drone)、6个Shell脚本及5份PDF/MD教程文档,整体大小160.8MB。已有200人学习下载,配套教程覆盖YOLOv5/v7/v8多版本环境配置、权重迁移训练及PyQt界面运行全流程,支持图片、视频与实时摄像头检测,数据集目录结构规范、标签格式统一,可直接用于科研验证或课程实验。 做固定翼无人机检测有一阵子了,圈子里最常看到的问题不是“该选哪个模型”,而是搜遍全网找不到一套能直接落地的完整流程。权重、数据集、训练教程、界面封装四样东西,往往得从四五个博主那里东拼西凑,而且很多开源权重只针对大疆那种旋翼机,换到固定翼场景效果立刻打折扣。
这篇文章就把我这段时间攒下来的完整方案摊开讲:YOLOv8训练固定翼无人机检测权重、2000张数据集的制作细节、从训练到PyQt界面部署的完整链路。适合刚接触YOLOv8但手里有明确检测需求的人,也适合那些已经跑通过官方demo、但不知道怎么把模型做成一个像样桌面工具的朋友。
1. 为什么固定翼无人机检测比旋翼机更棘手
先聊点务虚的,但这部分决定了你后面所有的技术选型。
固定翼无人机和常见的四旋翼无人机在检测任务里有本质区别。大疆那类旋翼机飞行速度慢、悬停多、机体结构复杂(四个机臂、云台、起落架都清晰可见),中近距离下检测框很稳定。但固定翼无人机有几个非常头疼的特点:
- 尺寸小:翼展通常在1到3米之间,在几百米外拍摄时,画面里往往只有十几个甚至几个像素。
- 速度快:巡航速度动辄每小时几十上百公里,运动模糊严重,帧与帧之间目标位移大。
- 背景复杂:固定翼多出现在天空、海面、山地等场景,云层、海面反光、山体纹理造成的虚警率远比普通目标检测高。
- 姿态多样:转弯坡度、俯冲、拉升都会让目标外形产生剧烈变化,侧面、背面、机头正对镜头时的特征完全不同。
这些特点叠加在一起,决定了你不能无脑套用COCO上训练出来的通用检测权重。COCO数据集里虽然有airplane类,但那是客机、小型螺旋桨飞机为主,和“小型固定翼无人机”在尺度、外观、拍摄角度上有很大差异。实测下来,直接用COCO权重在固定翼无人机画面上推理,漏检率能到40%以上,虚警率也不低——云层边缘、飞鸟都会触发误报。所以,自己准备数据集、自己训练一个专用权重,不是“锦上添花”,而是“必经之路”。
这个项目里我用的是YOLOv8s作为基础模型。为什么选s而不是n或m?n确实更快,但在小目标场景下精度下降得厉害;m精度好一些,但训练和推理速度对1660Ti这类显卡不太友好。s在精度和速度之间是最平衡的,实际测试下来单帧推理在GTX 1660Ti上大概20到30毫秒,完全够用。
2. 2000张训练集是如何从零建起来的
数据是检测项目的命根子。很多人在这一步就放弃了,因为标注枯燥、来源难找、整理麻烦。我分几个部分把这2000张数据集的完整构建过程讲清楚。
2.1 数据来源:自建拍摄+公开数据集筛选
这2000张图不是一次性从某个网站下载的,而是三个来源的混合:
- 自建拍摄:占600张左右。用无人机挂载摄像头从不同角度拍摄固定翼飞行画面,同时在起降场附近拍摄地面停机、滑行状态。这部分数据的价值在于目标姿态、光照、背景完全贴近真实部署环境,是模型精度的基石。
- 公开数据集筛选:占900张左右。VisDrone、Aeroscapes这些公开无人机视角数据集里有一定数量的固定翼目标,把这些图片筛出来重新标注。注意VisDrone里的类别标签比较粗糙,很多“固定翼”样本其实是直升机或者动力伞,需要人工二次审查。
- 网络搜索补充:占500张左右。搜航空展、航模比赛等关键词,搜集不同品牌、不同涂装的固定翼无人机图片,填补自建数据里机型单一的问题。
这里有个细节值得多说一句:网络图片不要直接拿来训,先做版权和清晰度筛选,再统一分辨率和格式。图片尺寸差距过大会导致训练时resize后目标尺度分布不稳定,影响收敛。
2.2 标注策略:小目标的标注方式决定模型上限
标注是整个过程里最容易出问题、也最影响最终质量的环节。我用的标注工具是Labelme和LabelImg,YOLOv8要求的是txt格式,每个标注文件对应一张图片,每一行格式是:
class_id x_center y_center width height注意坐标是归一化的,且是相对于图片宽高的比例。用LabelImg可以直接导出成YOLO格式,Labelme则需要通过脚本转换一次。
标注时有几个关键原则:
- 单类别标注,不区分机型。固定翼无人机不管型号、涂装、尺寸,统一归为“fixed_wing”一个类别。类别越多、样本越稀疏,训练越不稳定。
- 小目标标注框宁准勿大。目标只有10个像素左右时,标注框稍微偏大一点,模型学到的就是“一个大黑点”,检测框会严重偏大,导致IoU计算偏低、AP值虚低。我的经验是把目标放大到200%后再精确描框。
- 模糊目标也标注。运动模糊、远处小目标的确认度不高,但这类样本恰恰是提升模型鲁棒性的关键。只要人眼能确认“是固定翼无人机”,就标。
- 负样本单独建一个noise目录。我额外准备了几百张没有固定翼无人机的天空、云层、海面图片,在训练时混入作为负样本,显著降低了虚警率。这一点很多人会忽略,但对固定翼无人机这种“目标是天空中的小点”的场景特别重要。
2000张图一个人标注,每天投入3到4小时,大概一周到十天能完成。为了不浪费时间,标注前先按拍摄场景、天气、背景做一次预分类,然后轮流标注,避免同一批图片全部是晴天蓝天背景,导致模型对阴天、海面背景泛化能力差。
2.3 数据增强与数据平衡
2000张图片直接训练不是不行,但泛化能力会差一些。我在训练前做了以下几类增强:
- 几何增强:随机翻转、随机旋转、随机缩放。
- 色彩增强:亮度、对比度、色调的小范围扰动,模拟不同光线条件。
- Mosaic增强:YOLOv8自带的mosaic增强,把4张图拼成1张训练,对小目标检测的提升非常明显,相当于变相增加了数据量,也让模型适应目标被裁切的情况。
- 小目标专用策略:对小于32x32像素的目标,单独做2倍到3倍的子图放大增强,让模型有更多机会“看清”小目标的特征。
数据平衡方面,我按目标尺寸做了分层统计,确保“小目标样本”(目标面积小于图片面积1%)占比不低于总量的一半。否则训练出来的模型会对大目标过拟合,部署时看远处的小目标就失效。
3. YOLOv8训练调优与权重产出
数据准备好之后就是训练。YOLOv8的训练链路非常简单,但里面坑不少。
3.1 环境配置与版本选择
我用的环境是:
Python 3.9 PyTorch 2.0.x(实测2.1、2.13版本对YOLOv8兼容性也都正常) ultralytics 8.0.x(建议锁定版本,新版本偶尔会改默认参数) CUDA 11.8 GTX 1660Ti 6GB显存安装ultralytics直接pip就行,但注意它依赖的openCV版本在Windows上偶尔会有兼容问题,如果出现cv2.error: OpenCV(4.7.0)之类的报错,先升级或降级opencv-python试试。CPU版和GPU版不要混装,否则PyTorch检测不到CUDA。
3.2 数据集目录结构与配置文件
YOLOv8对数据集目录结构有固定要求,建议严格按这个来:
datasets/ fixed_wing/ images/ train/ # 1600张 val/ # 400张 labels/ train/ val/yaml配置文件fixed_wing.yaml:
path: D:/datasets/fixed_wing # 这里是绝对路径,相对路径在换机器跑时会报错 train: images/train val: images/val nc: 1 names: ['fixed_wing']这里有一个常见坑:path字段一定要写对。我见过无数人因为path写成了相对路径,或者train/val路径写错,训练时直接报空数据。
3.3 训练命令与参数调优
训练命令用的是ultralytics的标准CLI:
yolo train data=fixed_wing.yaml model=yolov8s.pt epochs=200 imgsz=640 batch=8 device=0几个关键参数的选择思路:
- model=yolov8s.pt:直接加载COCO预训练权重做迁移学习,而不是model=yolov8s.yaml从零训练。预训练权重能大幅加速收敛,在小数据集上尤其明显。可以理解为模型已经见过真实世界的纹理、边缘等基础特征,我们只教它“什么是固定翼无人机”这件新事。
- imgsz=640:这是速度和精度的平衡点。如果目标非常小,可以考虑用imgsz=960或1280,但这会显著增加显存占用和推理时间,1660Ti跑960基本是极限。我在640分辨率下配合切片推理(后面会讲到),效果已经不错。
- batch=8:6GB显存下的安全值。如果batch=16显存溢出,调成8。但注意batch太小会导致batch normalization不稳定,所以尽量不要低于4。
- epochs=200:对2000张数据来说,160到200轮已经足够,再长容易过拟合。训练过程中可以观察val精度曲线,如果连续50轮没有提升就可以提前停。
训练过程中的几个关键监控点:
- 观察train_batch*.jpg图片,确认mosaic增强后的图片和标注框对齐正常。
- 观察val_batch*.jpg预测结果,看有没有漏检、框不贴合的问题。
- 每轮结束看PR曲线和F1曲线,如果P和R的平衡点比较好,模型曲线下面积大,说明正负样本分类比较清晰。
3.4 训练常见问题排查
- 训练时loss为nan:大概率是学习率过大或batch太小导致梯度爆炸,把lr0从0.01调低到0.001试试。
- 显存不够:imgsz降到480,或者用yolov8n。
- 训练很慢:开AMP混合精度,1660Ti虽然不支持完整的TensorCore加速,但AMP仍然能有效省显存、提速度。
- 验证集mAP很高但实际效果差:检查是不是数据泄漏,训练集和验证集里混入了同一个视频序列中高度相似的帧,导致验证集“虚高”。
3.5 模型评估与最终权重产出
训练结束后,ultralytics会在runs/train/目录下生成多个权重文件:
- best.pt:验证集上mAP最高的权重,这个是我们最终部署要用的。
- last.pt:最后一轮的权重,一般不用。
最终我在自己的验证集上测得的指标大概在mAP50-95=0.63、mAP50=0.91左右。注意2000张单类数据、目标尺度偏小的情况下,这个指标是合理且可复现的。如果谁告诉你几千张数据mAP50-95能到0.9,要么是验证集太简单,要么是数据泄漏。
4. PyQt5检测界面的设计与实现
模型训练完只是完成了一半,实际使用中不可能每次都在命令行里跑推理。我用PyQt5做了一个简单的桌面检测工具,支持图片、视频和摄像头实时检测三种模式。这部分对不熟悉GUI编程的人来说门控比较大,但跟着做也不难。
4.1 整体架构:界面线程与检测线程分离
PyQt5界面开发最重要的一点:不要在UI主线程里做推理计算。
推理是耗时操作,如果直接在主线程里跑,界面会出现“未响应”状态,用户体验极差。我用了一个很朴素的主线程+QThread worker模式:
class DetectWorker(QThread): frame_ready = pyqtSignal(object) result_ready = pyqtSignal(object) def __init__(self): super().__init__() self.model = YOLO('best.pt') self.cap = None self.running = True self.source = None def run(self): if self.source == 'camera': self.cap = cv2.VideoCapture(0) elif self.source == 'video': self.cap = cv2.VideoCapture(self.video_path) elif self.source == 'image': self.detect_image(self.image_path) return while self.running: ret, frame = self.cap.read() if not ret: break results = self.model(frame, imgsz=640, conf=0.35) annotated = results[0].plot() self.frame_ready.emit(annotated) self.msleep(30) def stop(self): self.running = False if self.cap: self.cap.release()Worker线程把检测结果画好之后,通过信号发回主线程,主线程只需要把QImage显示到QLabel上。
def update_frame(self, frame): rgb_image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) h, w, ch = rgb_image.shape bytes_per_line = ch * w qt_image = QImage(rgb_image.data, w, h, bytes_per_line, QImage.Format_RGB888) self.video_label.setPixmap(QPixmap.fromImage(qt_image))4.2 界面布局与交互
界面布局用QWidget作为主窗口,左侧是控制面板,右侧是画面显示区:
- 控制面板包含:打开图片、打开视频、打开摄像头、停止、置信度阈值滑条。
- 画面显示区:QLabel显示检测结果,下方状态栏显示FPS和当前检测到的目标数量。
置信度阈值这个滑条很重要。固定翼无人机场景下,远处小目标的置信度天然偏低。如果固定写死0.5,很多真目标会被过滤掉;但如果降到0.2,又会产生大量虚警。做成滑条让用户根据实际场景动态调整,是桌面工具实用的关键之一。
4.3 推理速度优化
实时性是这个界面工具的核心指标。我在1660Ti上针对不同输入做了以下优化:
- 摄像头模式:跳帧处理。每读2帧才做一次推理,但显示帧仍然保持原帧率,这样视觉效果流畅,GPU负载也降下来了。
- 画面缩放:推理前把大尺寸画面resize到640x640,检测框坐标再映射回原图。这个YOLOv8内部已经处理了,直接传大图也可以,但会明显增加推理耗时,建议在摄像头源上对原始帧先做一次不超过1280像素宽度的裁剪缩放。
- 慢推理的原因排查:如果FPS比预期低很多,打开任务管理器确认GPU占用率。如果GPU占用率很低但CPU很高,说明推理在CPU上执行了,去检查PyTorch和CUDA版本配对。
4.4 将界面封装成exe
PyQt5界面做好以后,用PyInstaller打包成exe在自己电脑上跑没问题,拿到别人电脑上却各种闪退,这是新手最常见的坑。
我的打包命令:
pyinstaller -w -F --add-data "best.pt;." --add-data "fixed_wing.yaml;." main.py打包完成后,注意:
- 模型文件和yaml文件要放在exe同目录或者打包进exe,否则程序找不到权重会直接崩溃。
- 如果目标机器没有NVIDIA显卡,要在代码里做cuda不可用时的CPU回退,并适当降低检测优先级。CPU上YOLOv8s推理一张640图片大概100到200毫秒,还是能用的。
- PyInstaller打包出来的exe首次启动会稍微慢一点,因为要解压临时文件,不要误以为程序卡死了。
5. 部署到真实场景的坑与最终实测
训练完成、界面也OK了,但拿到实际场景中测试,还是有一堆意想不到的问题。这些问题单独拿出来说清楚,能省你很多时间。
5.1 小目标检测的终极方案:切片推理
前面提到固定翼无人机在远景下可能只有几个像素,这时就算用再好的权重,YOLOv8直接整体推理也容易漏检。我实际验证过几个方案:
- 整图推理:远距离目标检测率大概只有60%左右。
- 图像金字塔:多尺度缩放后分别推理再合并,检测率有所提升,但推理时间翻倍。
- 切片推理:把原图切成256x256或320x320的小块,分别推理,再把结果合并回原坐标系。检测率能提升到85%以上,代价是推理时间增加。
切片推理在固定翼检测场景特别有效,因为它相当于把“远处的小目标”放大成了“近处的中目标”。具体实现上,可以在PyQt工具的检测线程里加一个“精细模式”开关,开启后在上屏前对原图做切片推理。注意切片之间要保留少量overlap,比如20像素,避免目标正好被切分到两块中间导致漏检。
5.2 云层反光的虚警问题
实际测试中我发现虚警主要来自两种场景:
- 云层边缘:形状尖锐、亮度和天空差异大,容易被模型误认为无人机轮廓。
- 海面/湖面反光:阳光直射下的水面波纹,纹理和运动模糊后的无人机有点像。
解决方案是收集这两种场景的负样本重新训练,同时把推理置信度阈值从0.25提高到0.35。这个调整会稍微降低少量低置信度真目标的检出率,但整体误报数量的下降幅度更值得。我最终的权重在晴天蓝天场景下的虚警率大概是每100帧1到2次,阴天和海面场景稍高,但已经在可接受范围内。
5.3 模型导出与ONNX部署
如果需要部署到没有PyTorch环境的机器上,可以把best.pt导出成ONNX格式:
yolo export model=best.pt format=onnx imgsz=640ONNX推理可以用onnxruntime,比直接加载PyTorch模型快一些,尤其在CPU上:
import onnxruntime as ort session = ort.InferenceSession("best.onnx") input_name = session.get_inputs()[0].name pred = session.run(None, {input_name: input_blob})在这个PyQt项目中,我保留了双后端:优先PyTorch GPU推理,导出时用户可以自己勾选ONNX模式。ONNX模式在CPU上也能跑,适合没有独显的笔记本。
5.4 实测数据与经验总结
最后放一组我在固定翼无人机实际飞行画面上的实测数据,供你参考:
- 整图推理(640分辨率):平均单帧28毫秒,远距离目标漏检率约35%。
- 切片推理(精细模式):平均单帧120毫秒,远距离目标漏检率降到15%以下,但FPS只有8左右,适合对实时性要求不高的场景。
- CPU推理(ONNX,无GPU):平均单帧150毫秒,勉强可用。
- 检测框稳定性:运动模糊帧会出现检测框抖动,我加了一个简单的EMA框平滑,画面稳定很多。
整个项目做下来最深的感受是,训练检测模型这件事,真正拉开差距的不是网络结构、不是训练技巧,而是数据质量和对实际场景的理解。你可以换各种backbone、加各种注意力模块、折腾十几天的调参,但效果可能不如老老实实多标500张负样本、多测几个实际飞行场景。
如果你也想做这个方向,我的建议是:先理清你的部署环境和目标距离,再决定数据集规模和推理策略。如果目标距离很近(50米以内),2000张数据其实绰绰有余;如果目标是几百米外的俯视小目标,那切片推理、更高分辨率输入、以及专门的远距离样例数据才是真正的突破口。别一上来就追最新的改进模块,先把基准链路跑通,后续优化才有比较的基准。
本文还有配套的精品资源,点击获取