简介:这份资源面向计算机视觉学习者与目标检测开发者,聚焦在视频场景中识别与追踪无人机目标,可用于公共安全监控、军事侦察或科研教学等实战方向。压缩包共21个文件,约79.25MB,包含10个Python脚本、6个模型权重文件、2张效果图、1个演示GIF、1个MP4视频及1份README说明,覆盖数据预处理、样本裁剪、特征提取、SVM流水线、检测可视化等完整环节。已有180人学习下载。读者可获得可直接运行的源码与预训练权重,省去从零训练的时间成本;配套流程教程讲解参数设置与常见问题,效果展示直观呈现检测框、置信度与跟踪轨迹,帮助快速验证算法在不同场景下的表现。项目结构清晰,适合在现有代码基础上微调模型、替换数据集或进一步优化检测精度与实时性,是从理论到实践积累无人机目标检测经验的优质实战素材。
1. 视频里追着无人机跑:一套能落地的目标检测方案长什么样
你手头有一段无人机飞行视频,可能是巡检拍的、比赛录的、或者就是自己飞着玩的素材。现在你想让程序自动把画面里的无人机框出来——不管它是悬停、横滚还是高速穿越。这件事听起来像是个标准的 YOLO 任务,但真正动手你会发现,视频里的无人机目标有几个很烦人的特性:尺寸小、运动模糊严重、背景天空占比大导致对比度低、而且同一段视频里目标尺度变化剧烈。我见过不少人拿 COCO 预训练的权重直接推理,结果要么框不住,要么框到云朵上去。
这个方案要解决的问题很明确:给你一套从数据准备到模型推理再到视频输出的完整链路,让你能在本地跑通「视频中检测无人机目标」这件事。适合两类人:一是刚接触目标检测、想找一个完整项目练手的工程师;二是已经会训模型、但没处理过视频流推理和小目标场景的开发者。核心关键词就几个——无人机、目标检测、视频、模型权重、项目源码,后面每一章都会围绕它们展开。你不需要 GPU 集群,一张 8G 显存的卡就能跑起来。
2. 先搞清楚检测什么:无人机目标的四个技术难点与选型逻辑
2.1 视频目标检测和图像目标检测的本质差异
很多人觉得视频检测就是「把视频拆成帧,逐帧跑检测」,这个理解不算错,但漏掉了关键点。视频带来的额外问题是时序一致性和计算吞吐。逐帧独立检测会出现框在相邻帧之间跳动、闪烁的现象,尤其是无人机这种小目标,帧间 IoU 可能从 0.7 直接掉到 0.3。另一个问题是速度——一段 30fps、1 分钟的视频有 1800 帧,如果单帧推理要 50ms,整段跑完就是 90 秒,这还没算后处理。
常见的做法有两种:一是纯逐帧检测加后处理平滑(比如卡尔曼滤波或简单的 IoU 轨迹关联),二是用视频目标检测网络(如 FGFA、MEGA),后者精度更高但工程复杂度陡增。对于「无人机检测」这个具体场景,我一般推荐第一种方案,原因是无人机在视频中通常是单目标或少量目标,不需要复杂的多目标跟踪逻辑,逐帧检测加简单的轨迹平滑就够用了。
2.2 为什么选 YOLO 系列而不是两阶段检测器
Faster R-CNN 这类两阶段检测器精度确实好,但推理速度是硬伤。在视频场景下,你需要的不是每帧都完美,而是整体流畅且不漏检关键帧。YOLO 系列(从 v5 到 v8 再到更新的版本)在速度和精度的平衡上更适合这个任务。特别是 YOLOv8,它的 anchor-free 设计对小目标更友好,而且 Ultralytics 的工程封装做得足够好,从训练到导出 ONNX 再到推理,一条龙。
选型时要注意几个参数:输入分辨率建议 640×640 起步,如果无人机在画面中占比很小,可以提到 1280×1280,但显存占用会翻倍;置信度阈值初始设 0.25,视频场景下可以适当降到 0.2 以减少漏检;NMS 的 IoU 阈值设 0.45 是通用起点。
2.3 数据标注:无人机检测的标注策略
如果你要自己标数据,有几个坑先避开。第一,无人机的旋翼在运动时是模糊的,标注时框应该包含旋翼的模糊区域,而不是只框机身。第二,远处的小无人机可能只有十几个像素,这种样本要么放大分辨率标注,要么直接丢弃——标了也训不好。第三,注意区分「无人机」和「鸟」——这是最常见的误检来源,标注时遇到不确定的样本宁可跳过。
标注工具用 LabelImg 或 CVAT 都行,导出 YOLO 格式的 txt。每个标注文件对应一张图,格式是class_id x_center y_center width height,全部归一化到 0-1。如果你手头没有标注数据,可以用 COCO 里包含无人机的子集,或者从公开的无人机检测数据集里找——搜「drone detection dataset」能出来不少。
# 将 LabelImg 的 XML 标注转成 YOLO 格式 import xml.etree.ElementTree as ET import os def xml_to_yolo(xml_path, output_dir, class_map): tree = ET.parse(xml_path) root = tree.getroot() size = root.find('size') w = int(size.find('width').text) h = int(size.find('height').text) lines = [] for obj in root.iter('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') x1 = float(bbox.find('xmin').text) y1 = float(bbox.find('ymin').text) x2 = float(bbox.find('xmax').text) y2 = float(bbox.find('ymax').text) # 归一化并转为中心点+宽高格式 cx = (x1 + x2) / 2.0 / w cy = (y1 + y2) / 2.0 / h bw = (x2 - x1) / w bh = (y2 - y1) / h lines.append(f"{cls_id} {cx:.6f} {cy:.6f} {bw:.6f} {bh:.6f}") out_name = os.path.splitext(os.path.basename(xml_path))[0] + '.txt' with open(os.path.join(output_dir, out_name), 'w') as f: f.write('\n'.join(lines)) # class_map 示例:{'drone': 0}这段代码的逻辑很直接:读 XML,提取宽高做归一化,把左上右下坐标转成中心点加宽高的格式。参数上注意class_map要和你训练时的data.yaml里的类别顺序一致,否则类别会错位。归一化时用原图宽高,不要用缩放后的尺寸。
3. 从零跑通训练:环境、配置与关键参数
3.1 环境搭建与依赖安装
环境这块没什么玄学,但版本兼容性是个老生常谈的坑。我一般用 Python 3.9 或 3.10,PyTorch 选 2.0 以上的版本,CUDA 版本跟着 PyTorch 官方推荐走。Ultralytics 的包直接 pip 装就行,但注意它更新很快,不同版本之间 API 可能有细微差异。
# 创建虚拟环境 python -m venv drone_det source drone_det/bin/activate # Windows 用 drone_det\Scripts\activate # 安装核心依赖 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 pip install ultralytics opencv-python numpy tqdm # 验证安装 python -c "import torch; print(torch.cuda.is_available())"最后一行应该输出True,如果是False,检查 CUDA 驱动和 PyTorch 版本是否匹配。这一步翻车的人不少,血泪经验是:先确认显卡驱动版本,再去 PyTorch 官网查对应的 CUDA 版本,别凭感觉装。
3.2 数据集组织与 data.yaml 配置
YOLO 格式的数据集目录结构是固定的,不要自己发明。标准结构如下:
dataset/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── data.yamldata.yaml的内容:
path: ./dataset train: images/train val: images/val nc: 1 names: ['drone']nc是类别数,无人机检测通常就是 1 类。如果你的数据里还标了「鸟」或者其他干扰物,可以加类别,但建议先只做无人机单类,跑通之后再扩展。names的顺序必须和标注时的 class_id 对应,这个错了训练出来的模型会完全不可用。
3.3 训练命令与参数调优
训练命令本身很简单,但参数怎么设决定了你能不能训出一个能用的模型。
yolo detect train \ data=dataset/data.yaml \ model=yolov8s.pt \ epochs=100 \ imgsz=640 \ batch=16 \ lr0=0.01 \ patience=20 \ device=0 \ project=runs/drone \ name=exp1逐项说明:model=yolov8s.pt用的是小模型,如果你显存够可以换yolov8m.pt或yolov8l.pt;imgsz=640是输入分辨率,小目标多的话可以提到 1280,但 batch 要相应减小;lr0=0.01是初始学习率,YOLOv8 默认用余弦退火,这个值一般不用大改;patience=20表示 20 轮没有提升就早停,防止过拟合。
训练过程中重点看两个指标:mAP50和mAP50-95。前者是 IoU 阈值 0.5 时的平均精度,后者是 0.5 到 0.95 的综合。无人机检测场景下,mAP50 能到 0.85 以上就算不错了,mAP50-95 通常在 0.5-0.65 之间。如果训练集 loss 一直在降但验证集 mAP 不涨,大概率是过拟合了,减少 epochs 或者加数据增强。
3.4 训练过程中的常见异常与排查
训练时最容易遇到的问题是 loss 变成 NaN。原因通常是学习率太大或者数据里有脏标注(比如宽高为 0 的框)。解决办法是先检查标注文件里有没有异常值,然后把lr0降到 0.001 再试。另一个常见问题是显存溢出,报CUDA out of memory,这时候把batch减半,或者把imgsz降到 416 先跑通再调回来。
还有一个不太容易发现的问题:如果验证集的 mAP 一直是 0,但训练 loss 在降,大概率是data.yaml里的路径写错了,或者验证集的标注文件和图片没有一一对应。检查方法是随机抽几张验证集图片,用标注可视化脚本画出来看看框对不对。
4. 视频推理与结果输出:从单帧检测到完整视频
4.1 加载模型权重并做单帧推理
训练完之后,权重文件在runs/drone/exp1/weights/best.pt。推理可以用命令行,也可以写 Python 脚本。命令行适合快速验证:
yolo detect predict \ model=runs/drone/exp1/weights/best.pt \ source=test_video.mp4 \ conf=0.25 \ save=True \ project=runs/infer \ name=video1conf=0.25是置信度阈值,视频场景下可以降到 0.2 减少漏检,但误检会增多。save=True会把带框的视频保存下来。输出在runs/infer/video1/目录下。
4.2 用 Python 脚本做视频逐帧推理与自定义后处理
命令行够用,但如果你想加自己的逻辑——比如轨迹平滑、区域过滤、报警触发——就得写脚本。
import cv2 from ultralytics import YOLO model = YOLO('runs/drone/exp1/weights/best.pt') cap = cv2.VideoCapture('test_video.mp4') fps = int(cap.get(cv2.CAP_PROP_FPS)) w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) out = cv2.VideoWriter('output.mp4', cv2.VideoWriter_fourcc(*'mp4v'), fps, (w, h)) # 简单的帧间平滑:保留上一帧的检测框 prev_boxes = [] while cap.isOpened(): ret, frame = cap.read() if not ret: break results = model(frame, conf=0.25, iou=0.45, verbose=False) boxes = results[0].boxes # 绘制当前帧检测结果 for box in boxes: x1, y1, x2, y2 = map(int, box.xyxy[0]) conf = float(box.conf[0]) cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(frame, f'drone {conf:.2f}', (x1, y1-10), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2) out.write(frame) cap.release() out.release()这段代码的核心逻辑是逐帧读取、推理、绘制、写入。参数上conf=0.25和iou=0.45是通用起点,verbose=False关掉每帧的日志输出,不然终端会刷屏。如果你要做轨迹平滑,可以在循环里维护一个prev_boxes列表,用 IoU 匹配当前帧和上一帧的框,匹配上的做加权平均。
4.3 推理速度优化:从 30fps 到实时
视频推理的速度瓶颈通常在预处理和后处理,而不是模型本身。几个优化方向:一是把模型导出成 ONNX 或 TensorRT,推理速度能提升 30%-50%;二是用半精度(FP16)推理,显存占用减半,速度也有提升;三是把预处理(resize、归一化)放到 GPU 上做,减少 CPU-GPU 数据传输。
# 导出 ONNX 模型 from ultralytics import YOLO model = YOLO('runs/drone/exp1/weights/best.pt') model.export(format='onnx', half=True, imgsz=640)导出后的 ONNX 模型可以用onnxruntime-gpu加载推理,速度比 PyTorch 原生推理快不少。注意half=True需要 GPU 支持 FP16,老卡可能不支持。
5. 避坑指南:无人机视频检测的五个真实翻车记录
5.1 检测框闪烁严重,相邻帧框位置跳变
现象:视频播放时检测框在目标周围跳动,看起来很不稳定。原因:逐帧独立检测没有时序约束,小目标的特征在相邻帧之间变化大,导致检测结果不稳定。解决:加一个简单的 IoU 轨迹关联,当前帧的框和上一帧的框做 IoU 匹配,匹配上的用指数移动平均平滑坐标。如果闪烁仍然严重,考虑用卡尔曼滤波做预测和平滑。
5.2 天空背景下的误检率居高不下
现象:模型把云朵、飞鸟、甚至远处的建筑物尖顶框成无人机。原因:训练数据中负样本不足,模型没有学到「什么不是无人机」。解决:在训练集里加入纯天空、云朵、鸟类的负样本图片(不需要标注框,空标注文件即可),比例控制在正样本的 20%-30%。另外可以把置信度阈值从 0.25 提到 0.4,牺牲一点召回换精度。
5.3 小目标漏检严重,远处无人机完全检测不到
现象:画面近处的无人机能框住,远处的完全没反应。原因:输入分辨率不够,小目标在 640×640 的输入下只有几个像素,特征提取网络根本抓不到。解决:把imgsz提到 1280,同时在训练时开启mosaic和copy_paste增强,让模型见过更多小目标样本。如果显存不够,可以用切片推理——把大图切成小块分别检测再合并。
5.4 模型权重加载报错,提示类别数不匹配
现象:用自己训练的权重推理时报RuntimeError: Error(s) in loading state_dict。原因:训练时的类别数和推理时的data.yaml不一致,或者用了官方预训练权重但没改nc。解决:检查训练时用的data.yaml里nc是多少,推理时确保模型加载的类别数一致。如果是用官方权重做微调,训练时nc要改成你自己的类别数。
5.5 视频输出文件无法播放或花屏
现象:推理完保存的 mp4 文件用播放器打开是黑屏或者花屏。原因:cv2.VideoWriter的编码器参数和输入视频不匹配,或者输出分辨率设错了。解决:确认VideoWriter的frameSize和输入视频的宽高一致,编码器用mp4v兼容性最好。如果还是不行,可以先把帧保存成图片序列,再用 ffmpeg 合成视频。
6. 进阶技巧:用切片推理把远处的小无人机也框住
切片推理(SAHI,Slicing Aided Hyper Inference)是我在处理无人机小目标时最常用的技巧。原理很简单:把一张大图切成有重叠的小块,每块单独推理,最后把结果合并回去做 NMS。这样每个小目标在某个切片里会变成「大目标」,检测率大幅提升。
具体操作上,切片大小设 640×640,重叠率设 20%。重叠是为了避免目标被切在边界上导致漏检。合并时用 NMS 去重,IoU 阈值设 0.5 左右。代价是推理时间变成原来的 4-6 倍,所以适合对精度要求高、对速度要求不高的场景,比如事后分析而不是实时检测。
from sahi import AutoDetectionModel from sahi.predict import get_sliced_prediction detection_model = AutoDetectionModel.from_pretrained( model_type='yolov8', model_path='runs/drone/exp1/weights/best.pt', confidence_threshold=0.25, device='cuda:0' ) result = get_sliced_prediction( 'test_frame.jpg', detection_model, slice_height=640, slice_width=640, overlap_height_ratio=0.2, overlap_width_ratio=0.2 ) result.export_visuals(export_dir='sahi_output/')参数说明:slice_height和slice_width根据你的输入分辨率和目标大小调,目标越小切片越小;overlap_height_ratio和overlap_width_ratio控制重叠比例,0.2 是通用值,目标密集时可以提到 0.3。confidence_threshold可以比常规推理低一点,因为切片后误检会在 NMS 阶段被过滤掉。
验证切片推理效果的方法:拿一段有远处小目标的视频,分别用常规推理和切片推理跑一遍,对比检测框的数量和位置。如果切片推理多出来的框确实框在了无人机上,说明有效;如果多出来的是误检,就要调 NMS 阈值或者提高置信度。
我自己的习惯是:训练阶段用常规分辨率,推理阶段根据场景选策略——实时检测用常规推理加 FP16,事后分析用切片推理加高分辨率。这套组合拳打下来,大部分无人机视频检测的需求都能覆盖。希望帮到你。
本文还有配套的精品资源,点击获取