YOLOv11无人机检测实战:小目标识别、训练调参与部署
2026/9/15 15:08:18 网站建设 项目流程

简介:基于YOLOv11的智能无人机检测系统完整项目资源,面向从事图像识别、目标检测研发的工程师及科研人员,用于快速搭建可落地部署的无人机识别与安防监控方案。资源包共669个文件,包含Python源码(172个py)、模型配置(82个yaml)、权重文件(1个pt)、文档说明(369个md)及GUI界面相关组件,整体6.51MB,结构清晰,便于二次开发与学习。目前已有122人浏览学习。整套代码与文档覆盖了完整检测流程:支持图片、视频与摄像头实时检测,附带PySide6图形界面可调整模型与阈值,并提供了模型训练、推理与部署的代码框架及配套文档,适合作为课题设计、算法实证或项目参考。

1. 用yolov11做无人机检测,最先要解决的是“小目标”问题

监控大屏上出现一个只有十几个像素的黑点,人眼往往要盯两三秒才能确认那是一架无人机,而一套基于yolov11算法的智能无人机检测系统必须在两三百毫秒内完成从检出、框选到告警的全过程。无人机在视觉检测里恰好落在最尴尬的区间:目标小、速度快、容易和背景融为一体,典型的“低慢小”目标。把yolov11落成一套可用的检测系统,难点不在训练脚本本身,而在于网络结构如何选、数据怎么标、推理参数怎么调。这篇文章按我实际做类似项目的顺序来写,覆盖yolov11的模型选型、无人机数据集的组装、训练调参以及预测后保存和告警闭环,新手能跟着跑通,做过一段时间目标检测的人也能对照自己的参数设定找差距。

2. yolov11的网络结构对无人机检测意味着什么

2.1 检测头改为anchor-free后,小目标训练少了一个坑

无人机在画面里的尺度变化远大于行人和车辆。近处的大疆四轴能占到半个屏幕,300米外的微型穿越机只有几个像素。在旧版YOLO里,anchor的预设尺寸和长宽比需要根据标注数据重新聚类,聚类结果又和相机焦距、安装高度强相关,换个机位就得重算。yolov11沿用anchor-free设计,检测头直接用解耦分支回归目标的四条边,不再依赖预设先验框。

这对无人机检测有一个直接被感知的好处:不用再维护一套随场景漂移的anchor参数。模型在训练时通过回归损失自己学习目标的宽高分布,只要训练数据里覆盖了大目标和小目标,部署时换一个视野更窄的摄像头不需要重聚类。另一个改动是检测头的解耦,分类和回归走独立分支,避免两个任务互相干扰。低空场景里无人机和飞鸟外形接近,解耦头让分类分支可以有更高的判别独立性,从训练曲线上看,收敛更平稳。

2.2 C3k2与C2PSA在特征提取上补了什么

yolov11把之前的C3模块换成了C3k2。C3k2维持两个分支结构,一个分支做残差短路径保留原始信息,另一个分支通过多级拆分再融合来提取深层特征。这个模块用更少的参数量保留了特征融合能力,对无人机这类外形紧凑、纹理细节集中在桨叶和机架上的目标比较友好,细微纹理不容易在网络加深时被稀释掉。

深层部分引入了C2PSA模块。C2PSA是在特征图内部做空间自注意力,让模型不只盯着局部几个像素来判断“这是不是无人机”,而是结合周围云层、楼宇、植被的上下文综合判断。远距离无人机经常只有几个像素,局部纹理信息非常有限,如果没有全局上下文,模型很容易把飞鸟、风筝甚至镜头污点误判成目标。C2PSA对这类模糊判别的场景有实际提升,代价是推理耗时增加。边缘设备上跑yolov11n时,我会考虑关闭或替换这一层来换帧率,服务器端保持默认即可。

2.3 从n到x:先定算力再定精度

yolov11官方提供n/s/m/l/x五种尺寸,参数按深度和宽度因子缩放。实际选型时不是越大越好,而是先确定部署设备的推理预算。

模型深度因子宽度因子参数量(约)适用场景
yolov11n0.330.252.6M嵌入式设备、边缘盒子,要求实时
yolov11s0.330.509.4M中端GPU、安防NVR
yolov11m0.670.5020M服务器端,精度优先
yolov11l1.001.0025M离线分析、教师模型
yolov11x1.001.5057M最高精度、模型蒸馏

选择建议:监控场景实时视频流用s或m,m在小目标检出上明显强于s,但显存占用约翻倍。边缘设备选n,但要注意n对10像素以下的极小目标几乎不敏感,必须配合更高的输入分辨率和后处理优化。服务器端做非实时巡检用l起步,x留给蒸馏或困难样本挖掘。还有一个更实用的原则:同样算力下,优先把输入分辨率从640提到960,比直接换大尺寸模型对小目标的提升更明显。

3. 无人机数据集构造与标注规范:把“低慢小”变成可学习的样本

3.1 三路并行的数据来源:真实监控帧、公开数据、合成图像

无人机检测的数据集比行人或车辆难凑,核心原因是大多数监控场景里无人机出现的频率太低。我一般用三路并行来组:第一路是实际场景里的监控视频抽帧,覆盖早晚不同光线、顺光逆光、不同相机位姿,这部分占比最高,因为部署时遇到的场景分布主要靠它兜底。第二路是公开数据集中包含无人机、航空器类别的子集,清洗后并入训练集,用于扩充目标姿态的多样性。第三路是合成数据,把无人机贴图叠加到真实背景上,注意光照方向和阴影角度要和背景一致,否则模型学到的是贴图的边缘痕迹。

合成数据占比建议控制在三成以内。超过这个比例,模型容易把高对比度的矩形边缘误判成无人机,真机上误报率会明显升高。三类数据合并后按场景打散划分训练集和验证集,不能按来源划分,否则验证集和训练集的分布差异过大,指标会失真。

3.2 统一标注与格式转换:从VOC的XML到YOLO的txt

标注规则要先定死。无人机整体遮挡超过一半且无法判断外形的样本直接丢弃;旋翼旋转产生的模糊光影不单独标框,只标机身主体;远处的极小目标只要人眼能定位就要标出来,不标会让模型产生系统性漏检。类别名统一为小写的drone,避免混入大写变体导致类别数量膨胀。

标注完成后,大多数标注工具导出的是VOC格式的XML文件,yolov11的ultralytics框架需要YOLO格式的txt。下面这个脚本做一次性转换:

""" xml_to_yolo.py 将VOC格式标注转为YOLO格式txt 用法:python xml_to_yolo.py <xml_dir> <txt_dir> """ import os import sys from xml.etree import ElementTree as ET classes = ["drone"] # 类别列表,只保留无人机 def convert(xml_path, out_dir): tree = ET.parse(xml_path) root = tree.getroot() size = root.find("size") img_w = int(size.find("width").text) img_h = int(size.find("height").text) out_name = os.path.splitext(os.path.basename(xml_path))[0] + ".txt" with open(os.path.join(out_dir, out_name), "w") as f: for obj in root.iter("object"): cls = obj.find("name").text if cls not in classes: continue 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需要相对坐标而非像素坐标 cx = (x1 + x2) / 2 / img_w cy = (y1 + y2) / 2 / img_h w = (x2 - x1) / img_w h = (y2 - y1) / img_h f.write(f"0 {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}\n") if __name__ == "__main__": xml_dir, txt_dir = sys.argv[1], sys.argv[2] os.makedirs(txt_dir, exist_ok=True) for xml_file in os.listdir(xml_dir): if xml_file.endswith(".xml"): convert(os.path.join(xml_dir, xml_file), txt_dir) print("转换完成")

转换逻辑里有几个关键点。一是类别编号固定由classes列表顺序决定,当前只有无人机所以写死为0。二是x1、y1、x2、y2必须转成中心点加宽高的归一化形式,除以图片宽高保证数值落在0到1之间,否则训练时回归目标会失真。三是脚本对无效类别做了跳过,如果XML里混入了bird、kite之类的负样本标签,不会污染类别空间。

3.3 增强策略要偏向小目标

yolov11训练默认启用Mosaic增强,但对无人机数据集我会再追加几项针对性增强。

增强方法推荐参数对无人机检测的作用
Mosaic概率0.5,最后10轮关闭拼接多图,增加小目标上下文
CopyPaste概率0.3把无人机复制到新背景,扩充样本量
随机HSV扰动H±30,S±25,V±20适应早晚和逆光的光照差异
小目标过采样对短边小于32像素的目标重复标注并放大改善极小目标的权重占比

小目标过采样是需要手动处理的。Mosaic虽然能拼接图片,但目标在拼接后仍然是小尺寸,模型还是学不到足够的细节。常见做法是把包含极小目标的图片按区域裁剪放大1.5倍再塞进训练集,让模型有机会看到放大的桨叶纹理。代价是训练集体积增大,但收敛速度会更快。

4. 训练与调参:yolov11环境配置和核心参数怎么定

4.1 最小环境配置与第一个训练命令

yolov11环境配置比预期简单,用ultralytics这个库就能跑通全部训练和推理流程,不需要手动搭建网络结构。Python 3.10、PyTorch 2.x、CUDA 11.8以上这三样是基础。创建虚拟环境后安装ultralytics:

# 创建虚拟环境,避免污染系统Python conda create -n yolov11 python=3.10 -y conda activate yolov11 # 安装ultralytics,会自动拉取依赖的torch、opencv等 pip install ultralytics # 训练,用m尺寸做迁移学习 yolo detect train \ model=yolov11m.pt \ data=drone.yaml \ epochs=150 \ imgsz=640 \ batch=16 \ device=0 \ project=run/drone_det

各参数含义如下:model指定预训练权重,迁移学习在数据量不充足时收敛更快;data指向数据集配置文件,yaml里写好train和val的路径、nc=1、names=["drone"];epochs设150起步,后续根据验证集曲线决定是否加训;imgsz是输入分辨率,640是默认值;batch按显存调整,16对应约24GB显存,8GB卡建议降到8;device指定GPU编号。第一次训练建议用m,s在小目标上的表现明显偏弱,debug排错时不差那几分钟。

4.2 三个必调参数:imgsz、batch、epochs

这三个参数对无人机检测的影响最大,我每次换数据集都会先固定一组基准值再逐个调。

参数基准值调整方向影响
imgsz640小目标多时提到960输入分辨率翻倍,极小目标的有效像素变成4倍,显存约翻两倍
batch16显存不足降到8影响BN统计和收敛稳定性,太小会震荡
epochs150看mAP曲线决定太少欠拟合,太多过拟合且浪费算力

不建议动的参数是anchor相关配置。yolov11是anchor-free设计,强行修改anchor只会破坏训练稳定性。另外一个隐性问题在Mosaic增强,默认开启,但最后10到20轮建议通过配置文件里的mosaic=0.0关闭,让模型适应真实的单图分布,否则验证时遇到无增强图片会掉点。

4.3 从loss曲线和mAP指标判断模型是否健康

训练过程中要盯两组指标。一组是loss曲线,box_loss、cls_loss和dfl_loss三类损失都要下降,其中box_loss波动大是正常的,但如果持续上升而cls_loss在下降,优先怀疑标注框质量有问题,多半是中心偏移或宽高标错。另一组是验证集指标,mAP50反映整体检出能力,mAP50-95对边界框精度更敏感。无人机检测里mAP50达到0.85而mAP50-95只有0.3的情况很常见,说明模型能找到目标但框不够准,集中体现在小目标上。

遇到训练震荡,先查数据里是否存在空标签图片,即没有标注目标的背景图混进了训练集。yolov11对这类图片会输出巨大的分类损失,导致梯度异常。排查方法是在data.yaml配置里把train路径的图片和对应txt做一次数量匹配,数量对不上就是漏标了。

5. 推理部署与低慢小识别:预测后保存、NMS调优与告警演示

5.1 推理命令与预测后保存的完整写法

模型训练完成后,推理和结果保存直接用ultralytics的predict接口,关键参数是save、save_txt和save_conf,决定预测后保存的是图片、标签还是置信度:

# detect.py 推理入口 from ultralytics import YOLO # 加载训练阶段保存的最佳权重 model = YOLO("run/drone_det/weights/best.pt") # 对视频流做推理,逐帧返回结果 results = model.predict( source="camera_0.mp4", conf=0.25, iou=0.45, imgsz=640, save=True, # 保存绘制了检测框的视频帧 save_txt=True, # 保存类别和坐标到txt save_conf=True, # 在txt里追加置信度 stream=True # 视频流场景必须开,避免一次性加载全部帧 ) for r in results: for box in r.boxes: if int(box.cls) == 0 and box.conf >= 0.3: print(box.xyxy.tolist(), box.conf.item())

代码里的参数按实际部署场景调整。conf=0.25是置信度阈值,低慢小场景建议降到0.2到0.3之间,太高会漏掉远处小目标,太低会产生大量误报。iou是NMS阈值,默认0.45,多目标聚集时调到0.5到0.6让重叠框合并更充分。save_txt配合save_conf会把最终置信度写到txt,这个文件作为检测日志留存,后续做告警追溯时可以直接读取。stream=True必须开,否则对长视频推理会吃满内存。

5.2 低慢小场景提升检出的三个实践手段

手段效果代价
imgsz从640提到960小目标mAP提升3到8个百分点显存占用约两倍,推理延迟变长
多尺度推理尺度波动大的场景更稳推理耗时约三倍
连续帧状态机告警抖动大幅下降实现成本低

第一种是提升输入分辨率。GPU显存允许时,imgsz从640提到960对远距离“低慢小”目标几乎是最有效的一步,但帧率会下降,需要实测确认。第二种是多尺度推理,把单帧分别缩放到0.8倍、1.0倍、1.2倍输入模型,再用NMS合并三组结果。第三种是连续帧状态机,单个模型的输出只是原始检测框,未经平滑直接弹告警会导致画面闪烁、误报频出。

5.3 一个可演示的告警状态机与弹窗逻辑

演示系统要识别“低慢小”无人机并弹出告警信息,不能只靠单帧置信度,我通常加一个极简状态机:

# alert.py 告警状态机 class DroneAlert: def __init__(self, min_confirm=3): self.min_confirm = min_confirm # 连续命中帧数 self.confirm_count = 0 self.alerting = False def update(self, detections): if len(detections) > 0: self.confirm_count += 1 else: self.confirm_count = max(0, self.confirm_count - 1) if self.confirm_count >= self.min_confirm and not self.alerting: self.alerting = True x1, y1, x2, y2 = detections[0].xyxy[0].tolist() print(f"无人机告警 坐标=({int(x1)}, {int(y1)})->({int(x2)}, {int(y2)})") # 这里接前端弹窗或声光联动 elif self.confirm_count == 0 and self.alerting: self.alerting = False print("告警解除")

min_confirm设为3,即连续三帧检测到才触发告警;缺帧时只减一,不会因为单帧漏检就立刻解除。这样在远处小目标时隐时现的情况下,告警不会闪烁。坐标输出做一次取整,便于日志归档。如果要做持久化,把这一行输出改写成写入SQLite或JSON文件即可。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询