ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

基于YOLO11与PySide6的航空安保无人机检测系统实战

基于YOLO11与PySide6的航空安保无人机检测系统实战

1. 项目思路与系统整体设计

1.1 为什么需要"航空安保+异常无人机检测"这套系统

航班起降阶段是最怕"不速之客"的,这个不速之客就是乱入的无人机。机场周边的禁飞区虽然早就划好了,但总有人钻空子,而且无人机产业这几年爆发式增长,从最低几百块钱的玩具飞机到上万块钱的行业机,黑飞现象在各大机场周边屡禁不止。

传统的航空安保手段主要靠人眼盯监视器或者雷达探测,但人眼盯屏幕这件事,盯不了20分钟注意力就会断崖式下跌。雷达的问题则是贵,一个像样的机场雷达系统动辄几百万,而且对低慢小目标的探测效果并不理想。这时候计算机视觉结合深度学习的目标检测方案就凸显出价值了,用摄像头采集画面,用YOLO系列模型实时识别画面里有没有无人机,一旦发现马上报警,这套组合可以做到秒级响应。

基于YOLO11构建航空安保与异常无人机检测系统,本质上是给机场周边的监控摄像头装上一双"AI眼睛",让它持续盯着天空,识别出无人机目标后立即在PySide6界面中弹出告警、框出目标、记录时间点。这套系统我实际做完之后的感觉是,它不仅能用在航空安保场景,改造一下摄像头视角和数据标注,同样能复用在电力巡检、化工厂区低空防护、大型活动安保等场景,属于那种"一个项目吃多个场景"的典型。

1.2 技术选型为什么是YOLO11 + PySide6

YOLO系列从v5到v8再到现在的v11,已经成了目标检测领域的"国民级"框架。YOLO11之所以值得选,核心原因是它在COCO数据集上精度和推理速度的平衡又往前推了一截,尤其是小目标检测能力有了明显的加强。无人机在远距离画面里往往只占几十个像素甚至几个像素,属于典型的小目标,早期的YOLOv5原始版本在应对这种场景时漏检率比较高,YOLO11在骨干网络和检测头结构上做了专门优化,对小目标更友好。

另一个考虑是工程化效率。YOLO11在官方发布的框架里直接提供了训练、验证、导出等全套接口,从零开始搭一套检测系统的时间成本被压到了很低。我想强调的一点是:做这种实际项目,最忌"过度造轮子",与其自己写一套不成熟的特征提取器,不如拿成熟框架做二次开发,把精力集中到数据层面和业务逻辑层面,这样收益最大。

PySide6为什么不是Tkinter不是PyQt5?Tkinter做演示Demo尚可,但要做"能给别人演示、能打包分发、界面看起来不像是临时拼凑"的安保系统,Tkinter的控件和样式实在撑不住场。PyQt5和PySide6本质都是Qt的Python绑定,但PySide6是Qt官方支持的方向,对Qt6版本追踪最及时,LGPL协议对商用也更友好。界面这块,我会用QThread跑摄像头视频流迭代,用信号槽机制把检测结果塞回主界面,整个过程流畅不卡顿,这个后面实操环节细说。

1.3 系统模块架构与功能清单

整套系统拆开来看,核心是三个大模块:数据侧、模型侧、UI侧。

数据侧我准备了一个整理好的无人机检测数据集,包含有人驾驶飞机、无人机、飞鸟、天空背景这四类样本。为什么要有飞鸟?因为无人机和飞鸟在画面里的视觉特征非常接近,如果不专门做"飞鸟"这一类做负样本,模型很容易把鸟误判成无人机,你想想机场上空有多少鸟,没有负样本的话报警器基本停不下来,这是做这类项目最容易被忽略但又最致命的一点。

模型侧围绕YOLO11训练权重展开,支持Windows和Linux双环境推理。训练完成之后把权重导出为ONNX或者TensorRT格式,推理速度还能再提一截,我在中低端显卡上实测过,ONNX导出后FPS能保持在40以上,足够满足安保实时性要求。

UI侧是PySide6桌面界面,承载五个核心功能:本地视频文件检测、实时摄像头/RTSP视频流检测、检测结果截图留存、告警日志记录、模型权重切换。截图留存这一项我建议必须做,安保场景不允许"口说无凭",捕捉到的无人机画面必须落到磁盘上,最好再同步保存一帧原图和一帧标注图,后续取证也好复盘也好,都有据可查。

1.4 系统适用人群与部署场景

这套东西适合谁参考?第一类是在校学生做毕业设计或者竞赛项目,技术栈新、界面完整、代码路径清晰,稍微改改就能完成一套有演示效果的完整作品。第二类是安防行业的初级开发者,想快速了解从数据标注到模型落地的完整链路。第三类是机场、电力、化工等场景的安保方案集成商,把这套系统作为原型去谈项目,前期DEMO成本几乎为零。

我建议的硬件底线是:训练阶段有NVIDIA显卡,显存6GB以上即可(8GB更稳),推理阶段如果用CPU跑也能跑,但帧率会掉到10以下,安保场景还是建议上一块入门级显卡。操作系统Windows 11和Ubuntu 20.04以上都没问题,依赖项用conda或者venv隔离环境管理,尽量不要裸装在系统全局Python里,后面依赖冲突会让人头疼。

2. 核心难点拆解:无人机目标检测为什么难

2.1 小目标检测:远距离无人机只有"几个像素"

正常环境下无人机在摄像头画面里往往很小,尤其是机场周边这种开阔场景,无人机距离摄像头动辄几百米,在1080P画面里可能只占10×10左右的像素区域。如果用的是640×640输入分辨率,这个目标在下采样到80×80的特征图上可能就只剩一两个像素了,模型很容易直接把它当成噪声过滤掉。

YOLO11针对这类问题的解法,是在特征融合网络上做文章。它依然沿用类似FPN/PAN的特征金字塔思路,把高层语义信息回传给低层特征图,让小目标也能在高分辨率特征图上获得足够的响应。但模型结构的改进只是基础,真正决定小目标能不能被检测出来的,还是数据集里必须包含大量"小尺寸无人机"标注样本。如果数据集里目标框普遍偏大,训练出来的模型一到真实场景就歇菜。所以我准备的数据集里特意混入了多种尺度:大疆御系列那种较清晰的中型目标、远处玩具级无人机的小目标、以及目标只有8×8甚至更小的极难样本。

2.2 无人机与飞鸟的区分:最容易踩的坑

前面提到了飞鸟问题,这里展开细说。空中目标检测里最难的不是"找出天空中有什么",而是"区分那到底是无人机还是鸟"。两者在低分辨率下都是一个小黑点,运动轨迹也都属于非线性,摄像头抖动还会加剧判断难度。

我的处理思路是:数据集中单列一个"bird"类别,而且飞鸟样本的数量和无人机样本数量基本持平,甚至稍多一点。网络上已有的几个公开无人机检测数据集大多只标"无人机",没有把飞鸟作为背景负样本加入,直接用那种数据集训练出来的模型,拿到真实机场场景几乎没法用。我整理这套数据时从各类公开视频和实拍照片中截取了大量飞鸟画面,包括海鸥、鸽子、鹰类等常见机场鸟种,和无人机画面做混合训练。实际测试效果是:误报率从几乎不可用的每分钟十几次降到了每小时三五次以内,效果立竿见影。

2.3 数据集的构成、标注格式与模型性能基线

这套系统的数据集规格如下:总图片数量22000余张,无人机目标的独立标注框超过31000个,飞鸟目标标注框接近15000个。图片分辨率集中在720P到4K区间,涵盖白天、黄昏、逆光、小雨等不同天气状况。标注格式统一用YOLO通用的txt格式,每个标注文件与图片同名,内容为"类别ID 中心点X归一化坐标 中心点Y归一化坐标 宽度W归一化 高度H归一化",这种格式对后续做数据增强和模型训练最省事。

我用这份数据集训练YOLO11n和YOLO11s两个模型做过基线对比。YOLO11n参数量最小,推理速度快,但是小目标上的漏检率略高,平均精度mAP@0.5大概在78%左右。YOLO11s参数量比n大了约一倍,mAP@0.5能到86%左右,推理速度在GTX 1660上单图耗时大约12毫秒,实际视频流处理依然非常流畅。下面给个简单的对比:

模型输入分辨率mAP@0.5mAP@0.5:0.95推理耗时(单张)备注
YOLO11n640×64078.3%52.1%6ms适合低算力设备
YOLO11s640×64086.5%62.8%12ms推荐用于安保场景
YOLO11m640×64089.2%67.4%20ms高精度但需要显卡

安保场景我建议直接用YOLO11s,精度和速度的平衡最理想。如果算力允许且对漏检零容忍,可以上m版本。

2.4 数据增强与训练策略的调优经验

数据增强这块我用了几项对空中目标特别有效的策略。第一是Mosaic增强,把四张图拼成一张随机裁剪,强制模型学习在不同上下文里的目标特征。第二是随机水平和垂直翻转,天空场景里无人机朝向没有固定方向,翻转增强能有效提升泛化能力。第三是HSV色域扰动,把色调、饱和度、明度随机变化,模拟早晨、中午、黄昏的不同光线条件。

训练超参数上,我建议初始学习率设置在0.01附近,配合余弦退火调度,epochs设置150轮,前3轮做warmup热身后再进入正式训练。batch size根据显存来,6GB显存跑YOLO11s选8,8GB以上选16。一个值得注意的细节是,不管数据集里目标数量多少,训练时建议关闭YOLO框架默认的自动anchor匹配,让网络自己学习适合当前数据集的anchor尺度,我实际对比过,对于小目标占比高的数据集,关闭自动anchors后mAP能提升1到2个百分点。

3. 实操环节:从环境搭建到Pyside6界面跑通全流程

3.1 环境准备与依赖安装清单

实操第一步是搭环境。坦白说这个环节出问题概率最高,但也是最好排查的。我用conda做环境隔离,Python版本选3.10,这个版本和当前主流的PyTorch、PySide6都有良好的兼容性,太新太旧都有坑。

conda create -n yolo11_air python=3.10 -y conda activate yolo11_air pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121 pip install ultralytics pip install pyside6 pip install opencv-python numpy pandas

这里提一句,torch的安装源务必选对CUDA版本,如果你的显卡驱动支持CUDA 12.1,就按上面这条命令装。如果机器没有NVIDIA显卡,把torch的index-url换成CPU版本即可,推理一样能跑,就是慢点。

安装完成后建议马上验证三个关键依赖是否就位:显卡下运行python -c "import torch; print(torch.cuda.is_available())",输出True才说明GPU可用;运行python -c "from ultralytics import YOLO"验证框架装载正常;运行python -c "from PySide6.QtWidgets import QApplication"确认界面库OK。三步都通过再继续,后面所有问题都不会再往环境层面牵扯。

注意:PySide6界面代码里一定不要在主线程做模型推理,否则视频画面会一帧一帧卡成了幻灯片。务必用QThread把视频流读取和检测放到子线程里,主线程只负责接收信号、刷新画面和记录日志,我给出的源码中已经按这个思路封装好了。

3.2 数据集准备与YOLO11模型训练实操

数据集的组织目录我按YOLO工程惯例放:

data/ images/ train/ val/ labels/ train/ val/ data.yaml

data.yaml的内容是核心配置,必须写明类别数、类名和路径:

path: data/ train: images/train val: images/val nc: 4 names: ['airplane', 'bird', 'drone', 'background']

注意"background"这一类不是必须的,但它可以在训练过程中提供"负样本锚点",减少纯天空背景被误检的概率。如果你的数据集里已有大量没有目标物体的纯背景图片,且标注文件为空txt,那可以不单独加这一类;如果背景图很少,加一类"background"能起到稳定训练的作用。

训练命令一行就跑通:

yolo detect train data=data.yaml model=yolo11s.pt epochs=150 imgsz=640 batch=16 device=0 project=runs name=air_security

我在训练过程中会盯着几个关键指标看:第一个是train/box_loss和train/cls_loss,这两个损失如果不下降或者抖动太剧烈,说明学习率可能过高或数据有问题;第二个是metrics/mAP50(B),这个量级到了0.8以上基本就够用了。训练过程中会在runs/air_security下自动生成best.pt和last.pt,best是验证集上表现最好的权重,最后部署用best别用last。

3.3 用QThread搭建实时检测通道

界面这块核心代码是视频流线程。我定义了一个VideoThread,继承QThread,重写run方法:循环读取cv2.VideoCapture的下一帧,送入模型做推理,把标注后的画面结果通过Qt Signal发回主界面线程。PySide6的Signal可以携带QImage对象,直接把检测后的图像传给槽函数渲染到QLabel上。

class VideoThread(QThread): change_pixmap = Signal(QImage) new_log = Signal(str) def __init__(self, model, video_path=0): super().__init__() self.model = model self.video_path = video_path self.running = True def run(self): cap = cv2.VideoCapture(self.video_path) while self.running and cap.isOpened(): ret, frame = cap.read() if not ret: break results = self.model(frame, device=0, verbose=False) annotated = results[0].plot() rgb = cv2.cvtColor(annotated, cv2.COLOR_BGR2RGB) h, w, ch = rgb.shape qimg = QImage(rgb.data, w, h, ch * w, QImage.Format_RGB888) self.change_pixmap.emit(qimg) # 记录检测日志 for box in results[0].boxes: cls_id = int(box.cls[0]) conf = float(box.conf[0]) self.new_log.emit(f"检测到:{results[0].names[cls_id]} 置信度:{conf:.2f}") cap.release()

这段代码的边界条件是一个坑:QImage构造时第5个参数bytesPerLine必须显式指定为ch * w,否则图像会因为行字节对齐问题出现RGB通道错乱和撕裂效果,我一开始踩了很久,图像在界面上一直颜色发绿,查了半天发现就是这个参数没写。另外线程退出条件running和cap.isOpened()两个要同时判断,否则点击"关闭视频"之后线程还挂在那里,程序退不干净,会报QThread destroyed while running的错误。

3.4 PySide6界面布局与告警逻辑

界面布局我采用左侧视频播放区、右侧控制面板和信息面板的方案。左侧QWidget内嵌一个QLabel作为视频显示框,控制面板放"打开视频文件""打开摄像头""开始检测""停止检测""截图保存""清空日志"六个按钮。信息面板用QTableWidget展示检测日志,列分别为时间戳、目标类型、置信度、处理帧号。

告警逻辑我用两种手段叠加:一个是在日志表格里把无人机目标行用红色背景标记,另一个是当出现无人机目标时,右侧面板顶部的状态栏由绿色变成红色并闪烁文字"无人机告警"。出于安保场景的严肃性考虑,刷新告警状态时用了QTimer做周期性状态检查,确保2秒内没有新的无人机目标后自动恢复常态,避免告警一直挂着不消。

截图保存逻辑用了简单的时间戳命名法,每次点击按钮或者自动告警触发时,把当前帧写入snapshots/目录,文件名用timestamp + 类别 + 置信度组合,例如20250509_143122_drone_0.92.jpg。这套命名规则在后端检索历史告警时非常方便,按文件名就能粗筛出当天所有无人机告警记录。

3.5 模型推理速度优化与ONNX加速

推理速度是安保系统的生命线。YOLO11原生的PyTorch推理在RTX 3060上已经能跑到50帧以上,但如果部署到算力较弱的小型工控机,建议做一步ONNX导出:

yolo export model=best.pt format=onnx imgsz=640 opset=12

导出完成后,推理代码把YOLO('best.pt')换成YOLO('best.onnx')即可。实际测试中,ONNX在CPU推理模式下比PyTorch原生模式快30%到50%,因为onnxruntime针对CPU做了图优化和算子融合。还可以更进一步用TensorRT。但对于大部分实验室和演示场景,ONNX已经足够了。

这里提醒一点:PySide6的RTTI和onnxruntime在少数Linux环境下的libstdc++符号版本兼容性问题偶有出现,遇到就报GLIBCXX_3.4.29 not found,解决办法是检查onnxruntime的轮子版本与系统gcc版本是否匹配,必要时升到较新版本的onnxruntime。

4. 训练与部署中的高频问题与实战排障

4.1 模型漏检率偏高,尤其是航拍远处的小目标

如果你训练完发现远处无人机总是检测不到,第一反应不要去调模型结构,先检查数据集里小目标占比。我吃过一个很大的亏,刚开始自己拍的照片都是离镜头十米以内的无人机,模型训练出来以后拿到机场监控画面里一测,五米外的小目标全部漏检,后来增加了大量远处和超远处无人机样本才把问题解决。

另一个有效技巧是加入"随机裁剪放大"的数据增强逻辑,把原始图像中一块包含小目标的区域随机裁剪后放大成640×640输入给模型训练,相当于让小目标变得更visible,模型学习起来就不那么吃力。实践中这个策略能把小目标召回率提高8到10个百分点。

4.2 背景误检率高,经常把云朵、飞鸟报成无人机

误检率高的主要原因是训练数据中负样本不足。"负样本"不是指图片里没有目标,而是指图片里有类似目标的样子,但它不是你要的目标。飞鸟最典型。另外机场场景里还有气球、风筝、塑料袋、老鹰、甚至远处高速公路上跑的大卡车,在低分辨率下都有可能被模型误判为无人机。解决方案很笨但有效:从真实摄像头录一段持续数小时的视频,每秒抽3~5帧,人工把飞鸟和其他干扰物标出来,加进训练集重新训练一轮,误检率能显著下降。

我还尝试过一个思路:在检测后处理中增加目标尺寸过滤规则。由于安保场景关心的是半径5公里内的低慢小飞行器,太小的目标(比如小于6×6像素)大概率是远距离鸟类而不是无人机,直接过滤掉,这样能降低不少误报,但这个阈值要根据实际摄像头的焦距和部署位置灵活调整,不能一刀切。

4.3 PySide6界面推理卡顿与内存溢出问题

界面卡顿通常不在界面代码本身,而是把重活放到了GUI线程里。我一开始图省事,直接在按钮槽函数里调model(frame),结果画面帧率掉到个位数,窗口拖都拖不动。用上QThread之后问题彻底解决,所以判定这类问题优先检查有没有把推理放到子线程里。

内存溢出问题主要集中在长时间视频流的场景,循环读取视频帧时如果results对象没有及时释放,内存会稳步上涨。我的处理建议是每处理一定帧数后显式调用gc.collect(),另外在循环末尾把上一帧的numpy数组引用置空,让QImage和cv2的引用计数能及时归零。连续跑4小时以上,整个进程内存占用能稳定在1.5GB以内。

4.4 数据集路径与跨平台兼容性问题

换机器跑代码时最烦的就是路径问题。我的建议是所有路径统一用pathlib.Path管理,不要硬编码Windows下的反斜杠路径。代码里可以这样写:

from pathlib import Path BASE_DIR = Path(__file__).resolve().parent MODEL_PATH = BASE_DIR / "weights" / "best.pt"

另外data.yaml中的path字段默认是相对路径,如果训练时换了启动目录会报Dataset not found,建议在data.yaml里直接用绝对路径,但不利分享。折中方案是训练脚本中先os.chdir到项目根目录再执行训练命令,路径问题就能彻底避开。

4.5 常见问题速查表

现象直接原因排查与处理
损失不下降学习率过高或标注文件与图片不匹配先降到0.001试跑50轮,确认数据集标注合法性
显卡OOMbatch size过大或输入分辨率过高batch降到4,imgsz降到512,开启memory_efficient
图片颜色发绿/错乱QImage构造bytesPerLine参数错误显式传入ch * w参数
无法打开RTSP流网络源超时或编码格式不支持换用ffmpeg拉流,检查rtsp路径是否带鉴权参数
告警日志时间不对未设置系统时区日志时间统一用datetime.now()并指定时区

5. 项目后续扩展与个人实操心得

5.1 从检测到跟踪:加入多目标跟踪逻辑

纯检测框架只解决"有没有无人机"的问题,实战中还得知道"无人机从哪来、往哪去、路径是什么"。后续扩展最自然的一步是接入简单在线实时跟踪机制,比如ByteTrack或者StrongSORT,给每个检测目标分配ID,跨帧关联同一目标,形成轨迹。有了轨迹信息,安保人员就能判断这架无人机是穿越禁飞区还是悬停侦察,处置决策的效率完全不一样。

我在这套源码里预留了跟踪模块的接口,VideoThread处理的每一帧结果都可以直接喂给跟踪器。给读者的扩展建议是:跟踪器要跟检测置信度联动,低置信度的检测框可以先用IOU匹配锁到已有轨迹上,不要轻易开启新轨迹,否则漫天飞鸟会让轨迹ID飞速增长。

5.2 告警联动与多路视频并行

安保场景单路画面通常不够,机场周边至少同时监控四路到八路摄像头。扩展方向是把单监控线程改成多线程池,每个视频源一个线程,共享同一个模型实例做推理,告警信息汇总到统一的事件总线。多路并行时GPU显存占用是关键瓶颈,YOLO11s推理的显存开销在2GB以内,一张8GB显卡跑四路完全没问题。

告警联动方面可以做三层动作:日志落盘、截图备份、微信/邮件/短信推送。短信推送适合用消息队列中间件异步发送,避免阻塞检测主流程。我再推荐一个低成本联动方案:把告警事件写入SQLite数据库,另写一个监听程序做分发,这样扩展性比代码里直接发HTTP请求强很多。

5.3 关于这套系统的一些个人体会

整个项目从数据标注到界面跑通我大概用了三周业余时间,大部分时间花在了数据清洗和标注质量的反复检查上。有很多人觉得做AI项目就是调参、跑模型、看精度,但真正做过实际落地项目的人会明白,模型以外的工程工作占比往往超过70%。数据怎么整理、界面怎么跟线程配合、告警怎么不打扰人、路径怎么跨平台稳,这些细节决定了系统能不能真正被用起来。

这套系统的源码结构和数据处理流程,我尽量做了模块化拆分,模型的训练入口、数据预处理、UI界面、日志模块各自独立,读者拿过去改任何一块都不会牵扯到其他部分。最后再分享一个小技巧:YOLO11在推理时如果发现画面中有大量相似目标同时出现(比如鸟群),可以通过max_det参数控制单张图的最大检测框数量,设置成20就够用,能有效弱化成群飞鸟造成的误报警。

另外,数据集和模型的版权问题需要注意,公开数据集使用时都要仔细确认许可协议,商业部署场景尤其如此。这是很多项目后期出问题的隐患,提前规避比事后补救省心得多。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进