ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

无人机实时人体检测实战:YOLOv7与TensorRT部署全流程

无人机实时人体检测实战:YOLOv7与TensorRT部署全流程 简介这是一篇基于YOLOv7的无人机热红外人体实时检测学术论文面向计算机视觉、目标检测与无人机遥感应用的研究者和开发者。针对无人机热红外图像中目标尺度小、场景复杂、公开数据集稀缺等难题论文提出一种基于CNN架构的UAV TIR目标检测框架并借助FLIR相机采集地面图像与视频进行训练验证。实验表明在IOU0.5时检测人体平均精度达72.5%处理速度约161帧/秒并对不同无人机观测角度下的检测性能进行了评估。内容涵盖CNN、YOLO模型演化、热红外成像特点、无人机视角影响等关键技术包含从数据采集、模型训练到性能评估的完整研究过程可作为目标检测方向论文写作、模型选型与实验设计的参考资料。压缩包内为1个PDF文件大小2.01MB已有269人学习下载适合需要快速了解YOLOv7在无人机实时人体检测中应用方法的读者。1. 一张俯视图难倒多少实时检测无人机往下一看人体往往缩成十几个像素的暗色小点地面纹理、车辆顶棚、电线杆影子全都在和人抢注意力。尤其中午树影浓密人在树冠间隙里时隐时现。YOLOv7无人机实时探测人体要解决的不是“能不能认出人”的问题而是“在一帧画面里人只占 0.3% 的像素时能不能又快又准地告诉地面站‘那里有人’”。低空巡检、应急救援、农田作业现场监护都等着这个结果去驱动后续动作。我最早做这个方向是在一套四旋翼平台上的视觉模块最初直接拿 YOLOv5 顶上去发现飞高之后召回率掉得很快后来换成 YOLOv7 并重新调了小目标先验锚框才算把白天低空场景拉到能用的水平。这篇笔记面向两类人一类是想把 YOLO 系列模型搬上无人机做人员探测的开发者另一类是已经在做无人机视觉感知、但被数据标注和部署优化卡住的人。我会从模型选型讲到数据准备、训练、TensorRT 部署最后把五个高频翻车现场列清楚。2. YOLOv7为什么扛住了无人机视角模型选型与推理链路设计2.1 无人机视觉感知下的检测难题怎么落到算法选型无人机视觉感知和普通监控摄像头最大的差异是视角和尺度。监控摄像头平视为主人体通常占画面高度的三成以上无人机俯视时人体是一个长宽比接近 1:2 左右的小矩形在 1080p 画面上可能只有 20×40 像素。这意味着检测模型对微小目标要有足够的特征提取能力同时对锚框的长宽比分布要足够敏感。YOLOv7 在这两点上都比同期的 YOLOv5 做得更扎实。它的 E-ELAN 结构把不同感受野的特征层做了更充分的信息混洗浅层特征里的边缘和纹理能更顺畅地传到深层这对“只有十几像素的人”非常关键。重参数化结构让训练时保持大模型的表达能力推理时折叠成单个卷积层部署后不会因为模型体积损失速度。加上它继承了 YOLOv5 的 anchor-based 设计训练时能直观地把锚框改成俯视人体的尺寸分布而不用像 YOLOv8 那样依赖解耦头的隐式学习。我在选型时做过一次简单对比记录如下模型Anchor机制小目标表现部署资料训练调参难度YOLOv5自动锚框可自定义中等极多低YOLOv7自动锚框可自定义较好多中YOLOv8/YOLOv9anchor-free依赖感受野也多中最终选 YOLOv7核心原因是它的推理图更规整。重参数化之后模型在 TensorRT 里做 FP16 量化时数值稳定性好无人机上常用的 Jetson 平台跑起来不容易因为个别层的精度丢失出现输出抖动。这一点后文部署章节会专门展开。2.2 推理链路从图传到检测结果的串联很多人以为“无人机实时探测人体”就是把模型塞进机载电脑对着摄像头跑就行。实际上机载端算力有限图传链路又有延迟工程上更常见的做法是“机载轻量感知 地面端重推理”或“机载端直接推理后仅上传检测结果”。两种路线对模型的实时性要求不同但推理链路的骨架一致。我一般把链路拆成六段取流、预处理、推理、后处理、跟踪、叠加输出。取流阶段从相机或图传接收端拿到 H.264 帧常见做法是解码成 BGR24 后直接送入预处理预处理包括 resize 到模型输入尺寸、归一化、CHW 转置推理在 TensorRT 引擎上执行后处理解析出框、类别、置信度做 NMS 过滤跟踪环节用 ByteTrack 这类轻量算法给框分配 ID最后把框和 ID 叠加到视频流上回传遥控器或者地面站。无人机图像传输阶段的延迟很关键。如果图传本身有 120ms 延迟机载推理再花 30ms地面看到的框就会明显落后于真实位置特别是无人机快速平移时观感很差。所以我在设计链路时会把检测结果的时间戳和图传帧的时间戳对齐而不是简单地在末尾叠加。另外很多人忽略的一点探测器输出的坐标是像素坐标要让飞控或路径规划算法用起来还得结合无人机定位和姿态角做坐标转换。这部分通常在下游完成但模型侧要保证检测框稳定不能一抖三跳否则转换后的经纬度会在地面画圈。所以我在开发时把目标跟踪也纳入了“实时探测”的范畴检测只是前半段。3. 准备数据集并训练YOLOv7从VisDrone到自建俯视数据3.1 VisDrone等无人机数据集的获取与类别映射训练 YOLOv7 不能直接拿 COCO 的权重一跑了之摄像头视角的俯视分布和 COCO 的平视分布差太多。公开数据里最适合起步的是 VisDrone 数据集它专门收集了无人机俯视视角下的行人、车辆、自行车等目标覆盖不同高度和光照是无人机视觉感知方向绕不开的基准数据。这个数据集的标注里和“人”相关的类别有两个pedestrian 指站立或行走的人people 指一群人聚集时难以单独框出的个体。用 VisDrone 训练人体检测时最常见的做法是把这两类统一映射成 person 一类。原因很直接无人机俯视时人群分散站立时每个人是单独的 pedestrian但三五个人挨得近时数据集注释会标成 people。对探测任务来说两类最终都要触发告警没必要在模型里区分。我在处理时会把车辆、自行车、遮阳伞等其他类别的标注直接丢掉减少背景类的噪声。除了 VisDrone还可以补充红外或夜间数据。无人机夜间探测人体单靠可见光效果很差现在不少方案会挂载红外热像仪。人体红外传感器在热像图里的特征是一个明显的高亮区域模型完全可以学习。但这类数据公开较少常见做法是自己录制后标注或者用合成数据做预训练再微调。另外一些竞赛平台会发布无人机视角的性能评测数据可以作为验证集做交叉评估。VisDrone 原始标注是左上角和右下角的像素坐标YOLOv7 需要的是归一化的中心坐标和宽高。我一般会写个一次性转换脚本把原标注文件夹扫一遍按类别映射表过滤后直接写出 YOLO 格式的 txt 文件。3.2 标注转换、训练配置与调参要点下面的脚本是我常用的 VisDrone 转 YOLO 格式的模板处理了类别映射、坐标归一化和无效标注过滤三个问题。import os import numpy as np from pathlib import Path # 类别映射VisDrone的pedestrian/people都归一到person(0) CLASS_MAP {pedestrian: 0, people: 0} IMG_W, IMG_H 1920, 1080 # 按实际图片尺寸填 def convert_label(txt_path, out_path): lines open(txt_path, encodingutf-8).read().strip().splitlines() out_lines [] for line in lines: parts line.split(,) # VisDrone格式: x1,y1,x2,y2,score,class,truncation,occlusion x1, y1, x2, y2 map(float, parts[:4]) cls parts[5] if cls not in CLASS_MAP: continue if x2 x1 or y2 y1: continue # 过滤掉极端小目标训练更稳定 if (x2 - x1) * (y2 - y1) 16: continue x_center (x1 x2) / 2 / IMG_W y_center (y1 y2) / 2 / IMG_H w (x2 - x1) / IMG_W h (y2 - y1) / IMG_H out_lines.append(f{CLASS_MAP[cls]} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) if out_lines: Path(out_path).parent.mkdir(parentsTrue, exist_okTrue) Path(out_path).write_text(\n.join(out_lines), encodingutf-8)这段脚本的核心逻辑有三个。类别映射在一个字典里完成后续新增类别只改这里。坐标归一化除以实际图片宽高这是 YOLO 格式的前提。过滤面积小于 16 像素的目标是为了防止训练时小目标过多导致损失震荡。需要注意VisDrone 里有些标注框是严重遮挡或截断的如果直接拿进去训练会让模型学习到不完整的轮廓尤其是人群聚集场景。更稳妥的做法是丢弃 score 字段低于阈值或遮挡等级过高的标注。数据准备完训练命令我通常这样写python train.py \ --data drone_person.yaml \ --weights yolov7.pt \ --img 640 640 \ --batch-size 16 \ --epochs 120 \ --hyp data/hyp.drone.yaml \ --workers 8 \ --device 0drone_person.yaml 里需要指定 train 和 val 路径以及 nc1 和 names[person]。hyp.drone.yaml 是从官方 hyp.scratch.p5.yaml 改来的我只动了三个地方mosaic 从 1.0 降到 0.9mixup 从 0 提到 0.15fliplr 从 0.5 降到 0.3。理由无人机俯视画面里左右对称的人很多但翻转增强太过会让模型对影子方向产生混淆mixup 少量加一点能让模型在人群密集时更容易把两个人分开。输入分辨率我用 640×640。有人习惯直接用 1280 训练追求小目标精度但无人机机载端的 TensorRT 引擎在 1280 下延迟会明显增加我通常先 640 训一版做 baseline再在它基础上用迁移学习往 960 或 1280 提一档。训练时监控 loss 曲线和 mAP0.5如果前 20 轮 mAP 一直为零多半是数据里小目标太多、锚框分布不匹配此时应该检查 kmeans 自动聚类的锚框结果。自建数据是必须做的。公开数据集训练出来的模型在自己无人机悬停拍摄的真实视频上往往有偏差常见做法是录 3 到 5 段不同高度和光照的视频抽帧后标 2000 到 3000 个样本再与公开数据混合训练。标注可以用 CVAT 或 labelme 这类工具输出 COCO 格式后再转成 YOLO 格式。4. TensorRT部署YOLOv7实时性的最后一步4.1 导出ONNX与构建TensorRT引擎训练完的 PyTorch 权重在 Jetson 或工控机上直接跑速度和显存占用都不可接受。常规路线是先把 PyTorch 权重导出成 ONNX再把 ONNX 交给 TensorRT 做图优化和层融合生成 engine 文件。整个流程在黑盒里完成但有几个参数直接影响最终效果。YOLOv7 仓库自带导出脚本常见做法是带 grid 和 end2end 参数导出这样 ONNX 的输出端已经把锚框解码和部分后处理包含进去部署端只需要做 NMS。导出命令如下python export.py \ --weights runs/train/drone/weights/best.pt \ --img-size 640 640 \ --batch-size 1 \ --grid \ --end2end \ --simplify \ --topk-all 100 \ --iou-thres 0.45 \ --conf-thres 0.25--end2end 参数决定 ONNX 里是否嵌 NMS 逻辑。如果不加导出的是一个四维输出张量部署端要自己写解码加了之后输出直接是候选框结果形状大致是 (1, 100, 6)其中 6 对应 x1、y1、x2、y2、score、class。我的经验是无人机场景里加 end2end因为机载 CPU 资源紧张自己写 NMS 的 Python 版本会严重拖慢整体帧率。接着用 trtexec 构建引擎/usr/src/tensorrt/bin/trtexec \ --onnxyolov7_drone.onnx \ --saveEngineyolov7_drone.engine \ --fp16 \ --workspace4096 \ --minShapesimages:1x3x640x640 \ --optShapesimages:1x3x640x640 \ --maxShapesimages:4x3x640x640--fp16 是收益最大的一项设置。无人机平台功耗受限FP16 精度损失在人体检测这种粗粒度任务上几乎看不出来但推理速度能提升一倍以上。--minShapes 和 --maxShapes 用来声明动态 batch 的范围如果确认每次只推理一帧可以直接固定 batch 为 1省掉动态尺寸带来的额外显存开销。workspace 给 4GB 主要是给 TensorRT 做层融合时临时分配内存用显存小的 Jetson 设备可以降到 2GB。4.2 后处理与推理并流接入拿到 engine 文件之后部署端的核心工作是预处理、推理调度、后处理三件事。下面是一个最小可用的 Python 推理骨架用 PyCUDA 或者 PyTorch 的 CUDAGraph 都可以但核心逻辑一样。import numpy as np import tensorrt as trt def infer_frame(engine, frame_bgr): # 输入: 1080p BGR帧, 输出: 检测框列表 input_img cv2.resize(frame_bgr, (640, 640)) input_blob np.ascontiguousarray(input_img[:, :, ::-1]).astype(np.float32) input_blob input_blob / 255.0 input_blob input_blob.transpose(2, 0, 1)[None, ...] # 推理 output engine(input_blob) # 形状: (1, 100, 6) boxes output[0] # 过滤置信度 valid boxes[:, 4] 0.35 results [] for box in boxes[valid]: x1, y1, x2, y2 box[:4] # 将640坐标映射回1080p scale_x frame_bgr.shape[1] / 640.0 scale_y frame_bgr.shape[0] / 640.0 results.append((int(x1*scale_x), int(y1*scale_y), int(x2*scale_x), int(y2*scale_y), float(box[4]))) return results预处理里最容易出错的是颜色通道顺序。OpenCV 读出来的是 BGR模型训练时用的是 RGB推理前如果不做通道翻转检测结果会灾难性地变差表现为框满天飞但置信度很低。这类问题我遇到不止一次后来直接把翻转写死在预处理函数里所有部署脚本统一走这个入口。帧的输入来源机载端通常走 GStreamer 管道。大疆系列无人机常见做法是图传接收端输出 HDMI 信号接采集卡后模拟成 UVC 摄像头OpenCV 的 VideoCapture 能直接读到。如果走 RTSP 拉流则用 GStreamer 的 rtsp 源。两种方式在链路设计上没有本质区别关键是解码出的帧必须带时间戳否则框位和实际位置对不上。实时性上Jetson Orin NX 级别设备跑 FP16 的 YOLOv7 640 输入帧率能做到 25 到 35 之间具体取决于后处理和叠加渲染的优化程度。如果达不到先看帧拷贝和 resize 是不是用了 CPU这两项往往比模型推理更耗时。5. 无人机人体检测避坑指南五个高频翻车现场5.1 训练没几个迭代就出现 NaN 损失用 VisDrone 混合训练时常在十几轮后 loss 突然变成 nan日志里关键字是 nan classify loss 或 nan box loss。原因有两类一是数据里有大量极端标注比如框宽高为 0 或坐标越界二是学习率过高加上小目标梯度不稳定。解决方法是先过滤标注异常的目标再把初始学习率从 0.01 降到 0.005并开启 warmup。我还会在 hyp 文件里把 cls_pw 设成 0.5减小分类损失的梯度放大效应。5.2 低空能测、飞高十几米就全丢这是无人机人体检测最典型的翻车现场。原因是模型的感受野和锚框尺寸分布是按照低空视角调的飞高后人体占比迅速缩小原始特征图上可能只有一个像素点。解决办法不是盲目加深网络而是三管齐下输入分辨率提到 960 甚至 1280、把数据集按不同飞行高度分层采样、在训练时将 mosaic 增强里的随机缩放范围扩大。飞高丢目标这件事没有银弹只能靠数据和输入尺寸的适配。5.3 白天不掉点夜间直接失效可见光模型在夜间几乎不可用。无人机夜间探测人体成熟方案是切换红外热像仪输入然后单独训练一个针对热像图的检测头。热像图上人体是白亮团块和可见光的特征差异很大直接用白天模型迁移效果极差。我试过在可见光和红外图上做配对数据混合训练实际效果不如分开训练两个模型、根据输入源动态切换。如果只能一个模型那就把所有夜间数据都参与训练但代价是日间精度轻微下降。5.4 TensorRT 引擎构建时的黑匣子报错trtexec 构建引擎失败很常见报错往往是一大段 CUDA error 或算子不支持。多数情况下和 YOLOv7 导出时的 ONNX 算子版本有关。我遇到过最多次的是 --end2end 后导出的 ONNX 里包含 EfficientNMS 插件老版本 TensorRT 不认。解决办法是升级 TensorRT 到 8.5 以上或者导出时不加 --end2end把 NMS 放回部署端。引擎构建成功后一定要保存 engine 文件避免每次启动都重新构建。5.5 检测框能出但乱跳不是模型问题是后处理无人机悬停或小范围移动时检测框忽大忽小、ID 频繁切换视觉上非常不专业。模型输出本身可能没问题问题在跟踪算法参数和后处理逻辑。常见做法是引入 ByteTrack 并降低其匹配阈值让检测框在置信度略低时也能跟住上一帧的目标。同时可以做一个检测框时序平滑用平滑滤波把框的抖动压下去。要注意平滑系数太大会让框反应迟钝无人机快速转向时目标框会滞后我一般取 0.5 到 0.7 之间。6. 验证才算落地一种可复现的上板验证流程验证要分三层来做。第一层是离线视频回放把无人机录好的视频丢给推理链路记录每一帧的检测结果和耗时统计 mAP0.5 和每帧平均延迟并单独按目标像素面积分桶比如 20 像素以下、20 到 60 像素、60 像素以上三档看清模型主要丢在哪一档。这一步能快速暴露数据分布和前后处理的缺陷我每次调参都靠这份分桶报告决定下一步方向。第二层是硬件资源验证。在目标部署板卡上跑 30 分钟连续推理监测 GPU 利用率、内存占用、温度看有没有显存泄漏或降频。Jetson 平台特别要注意散热推理时间一长核心温度上去后频率会被压住帧率可能从 30 掉到 18。如果出现这种情况优先检查是不是 power mode 设置成了自适应模式。第三层才是真实飞行验证。固定飞行高度和路径让无人机沿预设路线扫过目标区域统计正确检出率和误报率。飞行时的运动模糊和多方向光照变化是离线视频无法完全模拟的这一轮总会暴露出一些意想不到的问题。上板前的参数检查表如下。检查项目标值失败时的处理预处理通道顺序BGR→RGB且归一化修正颜色翻转NMS 阈值0.45 到 0.5误检多就提高置信度阈值0.25 到 0.4漏检多就降低跟踪匹配阈值0.6 左右ID 乱跳时调整输入尺寸640 或 960达不到帧率就降我自己的习惯是任何模型改动都要先在分桶测试的表格上看到明确收益再去上真机。不要凭感觉反复改阈值那样会把参数折腾成玄学。验证流程跑顺之后这套链路可以继续接检测框到无人机导航的坐标转换或者作为无人机路径规划算法的感知输入。希望这份流程能帮你少走一些弯路早日让你的无人机实时探测人体方案从仿真视频里走到真实天空下。本文还有配套的精品资源点击获取
返回列表