资讯动态

基于YOLOv11与Django的无人机灾害救援人员检测系统

发布时间:2026/10/18 10:41:17 来源:尧图企业网站定制
1. 项目背景与整体设计思路无人机在灾害现场的价值不用我多说——地震、洪水、山体滑坡这类场景里地面人员在废墟中穿行又慢又危险无人机飞一圈几分钟就能覆盖很大区域图传回到指挥终端后原本靠人肉眼一帧一帧找幸存者的工作现在可以交给深度学习模型来自动干。这也是我做这个项目的初衷用一个基于YOLOv11的检测系统把无人机拍到的灾害画面直接变成“哪里有人的报警信息”同时提供图片、视频文件、摄像头实时画面三种输入方式做成带Web界面的完整系统。先说清楚系统解决的核心痛点。灾害场景下的人员搜救有几个特殊性目标小、遮挡重、背景复杂。无人机飞行高度一般在几十米甚至上百米画面里一个成年人往往只有几十个像素废墟瓦砾和衣着颜色相近人形轮廓容易被淹没再加上烟雾、灰尘、光线不均传统的目标检测算法在这种场景下几乎不可用。深度学习尤其是YOLO系列模型在这类任务的鲁棒性和速度上是最合适的平衡点。技术选型上我做了几层考虑。模型方面选了最新的YOLOv11而不是更早的版本最主要的原因是它在小目标检测能力和推理速度上都有提升同时官方库把训练、验证、导出、部署的链路做得非常顺能省去大量造轮子的时间。后端框架选了Django而不是Flask或FastAPI原因很实际这个项目不只是一个检测接口还要有用户管理、历史记录、结果可视化、任务状态管理这类Web功能Django自带的后台、ORM、模板机制能把这些事组织得很干净。前端没有用很重的框架直接HTML少量JavaScript就够了毕竟核心是检测能力而不是页面交互。整体架构上我把它拆成了三层。最底层是模型推理层负责加载训练好的权重、处理输入图像、执行检测、输出标注结果中间层是Django业务层接收上传的图片和视频、管理检测任务、处理实时视频流、保存检测记录最上层是展示层用户通过浏览器上传文件或查看实时画面检测结果以可视化的形式反馈到页面上。三层之间尽量解耦模型推理部分做成独立的Python模块不直接依赖Django的请求上下文这样以后想把推理服务单独拆出来做并发扩展也不伤筋动骨。我还专门把三路输入的实现方式分开考虑过。图片检测是同步请求简单直接视频文件检测受时长影响需要异步任务用户不用一直盯着页面等结果摄像头实时检测则是对延迟最敏感的场景单独走流式通道。三种模式共用一个推理核心只是输入源和数据走向不同。这套结构让系统的扩展性比较好之后加入新的输入源比如无人机RTMP推流或者网络摄像头只需要新增一个数据源适配器就行。2. 数据集准备与模型训练要点2.1 无人机视角数据从哪里来做过目标检测的人都知道模型效果的上限由数据决定。无人机视角和普通道路监控视角有本质区别俯拍角度下人的头肩特征更明显、正脸侧脸特征弱化尺度变化剧烈这些都需要对应的数据来让模型学会。我优先收集了公开的无人机航拍人员检测数据集这部分的图片是真实的俯视航拍场景包含了不同高度、不同密度的人群分布非常贴合项目场景。但仅仅靠公开数据还不够因为灾害场景有它独有的视觉特征。我补充了模拟灾害场景的数据增强包括对原始图片做随机旋转、裁剪、亮度对比度调整以及用拼接方式模拟废墟中衣暴露人员的外观。这里有个经验直接加网上随便找的灾区图片效果不一定好因为很多网络图片是新闻照片目标大小和无人机视角差异太大反而会干扰训练。数据标注上我用的是目标框标注只标“人”这一个类别。功能性的类别不要贪多搜救场景不需要区分“站着的”和“躺倒的”只要把注意力集中在召回率上。标注时特别注意了密集场景下的遮挡目标——两个重叠的人宁可框稍微大一点也要都标出来否则模型会在遮挡情况下学出错误模式。2.2 小目标检测的三个关键优化无人机视角最大的技术难关就是小目标。目标在图像中占比小特征信息少很容易被骨干网络层层下采样之后丢失。我试了三种手段来缓解。第一是输入分辨率。默认下YOLO系列使用640x640我直接把训练分辨率提到了1280或更大。实验数据显示在无人机俯拍数据集上分辨率从640提到1280后小目标的召回率能提升十个点左右代价是训练时间增加了约三倍推理速度也会下降。对于搜救场景漏报比延迟更要命这个代价值得付出。第二是马赛克增强策略。官方提供的增强模块里马赛克增强多图拼接本身就适合小目标场景因为它相当于把小目标在整图中的相对尺寸进一步缩小让我模型的尺度和尺度多样性都得到了增强。训练前中期开马赛克增强最后三十个轮次关掉让模型在接近真实分布的数据上收敛这个经验在实践中非常有效。第三是检测头优化。YOLOv11的结构已经针对小目标做了改善添加了更高分辨率的特征融合层。我抽样统计了训练集的目标框尺寸分布确保P2层输出的特征图对应的小目标匹配率最高。如果做数据统计时发现一半以上的目标框面积小于32x32像素那就必须把高分辨率特征层的权重调高或者干脆提高输入尺寸。2.3 训练参数的实际配置这里分享一组我实测好用的配置照抄基本不会出大错。预处理阶段图像缩放用letterbox填充而不是直接拉伸避免目标形变。优化器用带动量的SGD初始学习率0.01权重衰减0.0005训练轮次220个epoch前三个epoch用warmup稳定梯度。批次大小受显存限制我用的单卡设置了16配合梯度累积达到等效64的效果。类别只有一类所以类别权重不平衡问题不严重但我在损失函数里还是给正样本加了轻微加权让模型在背景占据绝大多数区域时不会过度偏向预测背景。训练过程的监控要看的指标不只是mAP更关键的是在小目标子集上的AP。官方验证工具能按目标尺寸分段统计精度我会额外关注小目标段的值。早期如果loss下降缓慢不要急着调学习率先检查数据加载是否正确比如标注有没有错位、增强代码有没有把框和图像弄失配。很多训练不收敛的问题根本不是模型问题是数据管线的隐藏bug。训练完成后导出模型时我会同时导出FP32和FP16版本。FP16在支持半精度推理的GPU上速度提升很明显而精度损失通常在1%以内。导出后一定要在真实场景图上做一次抽样测试不要只看验证集指标因为灾害现场的光线条件和数据集分布还是会差很多。3. 核心实现检测推理模块封装3.1 一个可复用的检测模块模型训练完之后最重要的工作就是把推理逻辑封装成一个干净的模块方便Django在不同场景下调用。我设计了一个检测类初始化时加载一次权重之后所有请求都复用同一个模型实例。这里有个最常见的坑千万不要在每次检测请求里重新加载模型一个两百兆的权重文件加载就要几秒实时性完全没法保证。推理流程上我按标准流程输入图像转为RGB、保持宽高比缩放并填充到模型输入尺寸经过模型前向推理获得预测框和置信度执行非极大值抑制去掉重复框再把框坐标反算回原始图像坐标最后用字体和边界框绘制结果图。置信度阈值我设了0.25针对灾害场景的漏检敏感度如果漏检多就降到0.15这会换来更多误检框在搜救场景里宁多勿少。import cv2 import numpy as np from ultralytics import YOLO class DisasterDetector: def __init__(self, weights_path, conf_thres0.25): self.model YOLO(weights_path) self.conf_thres conf_thres def detect_image(self, image_bgr): results self.model.predict( sourceimage_bgr, confself.conf_thres, imgsz1280, verboseFalse ) boxes results[0].boxes if boxes is None: return [], image_bgr coords boxes.xyxy.cpu().numpy().astype(int) scores boxes.conf.cpu().numpy() annotated results[0].plot() return list(zip(coords, scores)), annotated实际使用中我发现用results[0].plot()画的框虽然方便但自定义程度太低无法在框上叠加“人员编号”或者置信度百分比。后来我改成从boxes里取坐标自己用OpenCV画框和标签这样既能控制字体大小也能在系统里把目标框的坐标数据存到数据库方便后续做统计分析。如果需要保存原始的小图目标裁剪也是从坐标这一步开始做的。3.2 推理加速经验谈单张图片检测的速度在普通显卡上跑到50毫秒以内问题不大但视频流场景对帧率要求更高我这里用两个方法做了加速。第一个是导出端到端模型开启模型内置的NMS后直接在GPU上完成全部后处理。这个方法能省去一部分Python层的运算开销让单帧推理从约40毫秒压到30毫秒缺点是置信度阈值和IoU阈值在导出时就要固定运行期不能再调。第二个是帧间跳帧策略。无人机视频的帧率一般是30fps但画面中目标的相对位置变化没那么快我实际测试下来每6帧检测一次中间帧直接复制上一帧的结果画面观感几乎没有差别系统负载却降到原来的六分之一。这个策略在指挥终端大屏观看场景非常实用前提是无人机不要飞得太快否则跳帧会导致目标拖影明显。如果追求完美流畅可以用跟踪算法对检测框做帧间关联给每个目标一个ID这样跳帧期间目标能平滑跟随。CTRLF搜索一下这些优化代码单独做成配置文件用参数控制是“全帧检测”还是“跳帧检测”保证不同使用场景下系统的灵活性。4. Django整合图片、视频、摄像头实时三通道4.1 Django项目结构设计把检测模块放进Django时项目目录我是这样组织的disaster_detection/ ├── detection/ │ ├── services/ │ │ ├── detector.py # 推理核心封装 │ │ ├── video_processor.py # 视频文件检测 │ │ └── stream_manager.py # 实时流检测 ├── app/ │ ├── views.py # 视图函数 │ ├── models.py # 检测记录模型 │ ├── tasks.py # 异步任务 │ └── urls.py ├── static/ │ ├── uploads/ │ └── results/我坚持把业务代码和模型推理彻底隔离视图层只关心HTTP请求和响应不关心模型怎么工作。这样做的直接好处就是测试很方便单独在命令行里对detector模块跑单元测试不需要启动Django服务。另一个受益点是后续如果想把推理换成TensorRT只需要改detector.py的内部实现对外接口不变。4.2 图片检测接口图片检测最简单也最常用。用户在页面上传图片Django接住文件保存到上传目录然后调用推理模块把检测结果图返回给页面展示同时把检测到的人员数量、每张图的目标坐标、置信度等元数据存进数据库。这个流程里我特别注意文件上传的安全校验限制最大文件为20MB并通过扩展名和后缀白名单双重判断文件类型防止非法上传。数据库表设计上我用一张Task记录字段包括任务类型image/video/stream、状态pending/running/finished/failed、输入文件路径、结果文件路径、检测人数统计、创建时间。这样用户在页面上可以回看历史检测记录也方便做数据统计比如一片区域的多次飞行记录里哪些位置出现人员概率高。这个功能在实际救灾指挥中其实很有价值能辅助规划搜索路径。4.3 视频文件与摄像头实时检测的实现方式视频文件检测如果同步做一个几百MB的视频可能要处理几分钟HTTP请求早就超时了。我改成异步任务模式用户上传视频后立即返回“任务已创建”后台任务逐帧读取视频每隔一定帧数执行检测结果帧合成为一段标注后的新视频同时把检测到的目标数随时间变化的曲线图保存下来。完成后页面自动轮询任务状态发现finished就显示结果下载链接。这里的轮询我用了简单的Ajax定时请求每两秒查一次功能上完全够用暂时不需要引入重量级消息队列。摄像头实时检测是技术含量最高的一路。我评估过两种方案一种是前端把摄像头的视频流用WebSocket推给后端后端每帧检测后把带框画面推回前端另一种是后端主动拉取摄像头RTSP流处理后再推给前端。实际项目中后者更稳定因为Django本身是同步框架对接WebSocket需要额外引入通道库项目复杂度会明显上升。对于常规局域网摄像头或者USB摄像头我用OpenCV在后台线程里读取视频流帧图像送入检测模块标注后的画面通过流式响应发送给前端img标签直接显示。用multipart/x-mixed-replace的MIME类型实现视频流回传浏览器无需装插件就能直接展示。实测在局域网环境下这个方案的延迟可以控制在200到400毫秒对于救援指挥场景完全可以接受。def video_feed(request): stream_url request.GET.get(url) return StreamingHttpResponse( generate_frames(stream_url), content_typemultipart/x-mixed-replace; boundaryframe )generate_frames是一个Python生成器内部完成一帧读取、检测、画框、编码JPEG的循环。关键在于生成器要放在独立线程中运行并且设置一个线程安全的终止标志否则客户端断开连接后后台线程还一直跑最后堆积成资源泄漏。踩过一次这个坑之后我专门加了客户端断连的长轮询超时机制连接超过10秒无响应就主动清理线程。4.4 并发与资源控制Django默认的多线程模式会导致一个问题如果有多个用户同时上传图片或者同时看视频流模型推理会并发执行而模型在GPU上并不能真正并行反而会因为线程切换频繁导致吞吐量下降。我在detector.py里用了一个足够大的线程锁保证同一时刻只有一个检测请求在执行。这个操作看起来粗暴但实际效果好排队等待的请求响应时间反而比让它们一起抢GPU更快更稳定。显存控制上加载模型时设置torch.cuda.set_per_process_memory_fraction给模型推理限定一个最大显存占用比例防止视频流长时间运行累积显存碎片导致OOM。这个方法没有银弹关键还是实测调整比例留足余量给系统其他组件。5. 常见问题排查与避坑实录训练阶段和部署阶段我分别踩过不少坑整理几个典型的希望能帮后来的人少走弯路。问题一训练loss不降或震荡。我先检查了数据管线的增强逻辑发现马赛克增强在某次配置修改后导致坐标框与图像不同步框里的内容根本不是对应的人。这种bug不打印增强中间结果是很难发现的。我的排查方式是写一个可视化脚本把增强前后图像和框直接画出来看数据没问题再去怀疑网络结构。问题二小目标漏检严重。如果推理结果里目标低于某尺寸时就检测不到优先检查输入分辨率是不是被API默认值覆盖了。我有一次在代码里明明设置了imgsz1280但预测时不小心传入了新通道的预处理数据导致分辨率回到了640。另一个常见原因是模型在导出时开启了半精度而某些GPU的半精度算子对小目标特征图有精度损失这种时候要对比FP32和FP16在小目标子集上的置信度差异。问题三摄像头视频流长时间运行后延迟越来越大。一开始我以为速度变慢是模型的推理时间增加了后来发现是OpenCV读取线程里的缓冲区会无限积压帧解码速度赶不上的时候旧帧一直堆积等GPU闲下来处理的是过期画面。解决方案是在读取线程里做一个简单的队列满了就丢弃最旧帧保证后端处理的永远是最新画面而不是积压的早先帧。问题四连续任务导致进程内存越来越高。Django开发模式下可能出现这个问题主要原因是测试期间每次调试都往结果目录里写大图没用完的文件越来越多。部署时一定要加定时清理策略保留最近N个任务的结果文件。问题五多设备并发访问时Web页面卡死。排查发现卡死的根因不是模型推理而是文件系统在高并发写入时锁冲突Django默认的SQLite数据库在高并发场景下也会出现锁等待。部署到生产环境后我迁移到了独立的数据库服务并把结果文件写入改成先写临时文件再原子改名问题就消失了。实际项目部署时还有一点心得分享。整个系统不应该只在一台机器上跑推理服务、Web服务、数据库分开部署更可控。模型推理以API形式暴露给Django调用将来有第二路无人机接入时只需要横向扩容推理服务节点即可。如果要做成更完整的救援工具可以考虑加一个目标跟踪模块对检测到的人员做跨帧ID关联能输出人员移动轨迹。更进一步如果把检测框送到分类网络里再判断一下人员姿态可以区分“能交流”和“疑似受伤”这对指挥决策会有更大帮助。我个人做完这个项目最大的体会是模型训练只占整个工作量的四成Django集成和工程化要花另外六成时间。很多人把精力都放在刷精度上忽略了系统的稳定性、错误处理和部署运维而这些才是决定一个系统能不能在真实场景中落地的关键。做这类项目时一定要从一开始就站在“我的系统要让一个不会敲代码的操作员去用”的立场去设计交互和容错这个思路比任何花哨的模型技巧都重要。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑