news 2026/10/1 2:57:49

Qt+FFmpeg+OpenCV‑DNN 实现本地或 RTMP/RTSP 实时 YOLOv5 目标检测播放器

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Qt+FFmpeg+OpenCV‑DNN 实现本地或 RTMP/RTSP 实时 YOLOv5 目标检测播放器

一、前言

本项目完整实现工业可用的视频 AI 播放器:FFmpeg 原生解码视频流,独立解码线程、独立 AI 检测线程,队列满丢弃旧帧,断流指数退避重连,本地视频 / 图片也支持检测,QPainter 绘制检测框,可直接编译运行,适合二次开发。

二、展示

本地视频

在线视频

三、项目简介

RTMPFaceYOLO:Qt + FFmpeg + OpenCV DNN,拉取 RTMP/RTSP/HTTP 直播流、本地视频、图片,运行 YOLOv5 ONNX 目标检测,画面叠加检测框、类别、置信度,左上角悬浮展示解码 FPS、检测 FPS、单帧推理耗时。

3.1 核心功能

  • 输入源:RTMP / RTSP / HTTP 网络流、本地视频文件、单张图片
  • AI 推理:OpenCV DNN 加载 YOLOv5s‑ONNX 模型,COCO80 类目标检测
  • 多线程隔离:UI 渲染线程、FFmpeg 解码线程、YOLO 检测线程完全分离
  • 流稳定性:RTSP over‑tcp、低延迟参数配置;网络断开指数退避自动重连
  • 背压处理:检测队列有界,队列满丢弃最旧帧,永远处理最新画面,延迟不会累积
  • 可观测性:实时统计解码 FPS、检测 FPS、推理耗时,区分 “无检出” 和 “未执行推理”
  • 本地文件播放:按原视频帧率做时间对齐播放,不会倍速飞速播放
  • 资源安全:FFmpeg 资源统一释放,跨线程自定义结构体元类型注册,信号槽安全传递检测结果

3.2 技术栈

  • C++ / Qt Widgets
  • FFmpeg:视频流解码、格式转换 sws_scale
  • OpenCV DNN:YOLOv5 ONNX 推理,letterbox 预处理、NMS 非极大抑制
  • 构建:CMake/qmake,Windows/Linux 均可编译

四、目录结构

RTMPFaceYOLO/ ├── src/ # 源码 │ ├── main.cpp # 程序入口:命令行解析、元类型注册、默认拉流地址 │ ├── videoplayer.h/.cpp # VideoPlayer(UI+渲染)+ DecodeThread(FFmpeg 解码线程) │ ├── detectthread.h/.cpp # DetectThread(有界队列 + 抽帧检测线程) │ └── detector.h/.cpp # Detector(OpenCV DNN 封装:加载/预处理/推理/后处理) ├── models/ │ ├── yolov5s.onnx # fp16转fp32实际加载的模型(fp32, COCO 80 类, 输入 640×640) │ └── yolov5s_orig_fp16_opset17.onnx # 原始备用 ├── bin/ # 运行时输出(exe + Qt/FFmpeg/OpenCV dll) ├── build/ # 构建中间产物

五、类职责说明

类文件职责
VideoPlayervideoplayer.cppUI 主窗口;管理解码、检测线程生命周期;模型路径查找;接收帧与检测结果;QPainter 绘制框标签;FPS 悬浮统计
DecodeThreadvideoplayer.cppQThread 子类;FFmpeg 拉流解码;sws 转 RGB24;发送sigImage(QImage);断流指数退避重连;本地视频帧率同步
DetectThreaddetectthread.cppQThread 子类;内置 Detector;有界队列,满丢旧帧;按时间间隔抽帧推理;信号回传检测结果
Detectordetector.cpp非线程安全;ONNX 模型加载、letterbox 预处理、推理、置信度过滤、NMS、坐标反映射;仅在检测线程串行调用
Detection结构体detector.h单目标检测结果:原图 QRect 框、类别 ID、置信度;需要Q_DECLARE_METATYPE支持跨线程信号槽

六、整体数据流

┌─────────────┐ sigImage(QImage RGB888) ┌──────────────┐ │ DecodeThread│ ─────────────────────────► │ VideoPlayer │ │ (FFmpeg解码) │ │ slotShowImage └─────────────┘ └──────┬───────┘ │ submit(img) ▼ ┌──────────────┐ │ DetectThread │ │ 有界队列+抽帧 │ └──────┬───────┘ │ Detector::detect() │ ├─ preprocess: letterbox→640×640→blob │ ├─ forward(): ONNX 推理(计时) │ └─ postprocess: 阈值过滤→NMS→坐标反映射 ▼ sigResult(QVector<Detection>) ┌──────────────┐ │ VideoPlayer │ │ slotDetection│ │ → render() │ QPainter 画框+标签 └──────────────┘
  1. main.cpp解析命令行流地址,调用VideoPlayer::open(url);
  2. 如果是图片执行单次检测;视频 / 网络流启动DecodeThread,开启检测则同时启动DetectThread;
  3. 解码线程输出 RGB888 格式QImage,信号发送给 UI 线程;UI 保存最新帧,把图像提交给检测线程队列;
  4. 检测线程做时间限流(距离上次推理不足 100ms 直接跳过),调用 Detector 推理;
  5. 推理完成通过信号把检测结果回传给 UI;UI 保存上一次检测结果,使用QPainter绘制矩形框、类别标签底色,刷新界面显示。

关键点:检测是旁路尽力而为任务,画面流畅性完全由解码线程保障,检测慢不会拖慢播放。

七、核心设计思路:视频流如何做到不卡顿

现实场景解码 30FPS,YOLO CPU 推理只有 3‑6FPS,如果每帧都推理或者无限队列,延迟会越来越大。本项目采用三流水线并行 + 丢帧背压策略。

表格

环节实现机制
解码不阻塞 UIFFmpeg 解码放在独立QThread,仅通过信号发送 QImage,UI 线程只负责渲染
解码不阻塞检测检测独立线程,有界队列做解耦
检测慢不拖累播放队列设置上限,队列满丢弃最旧帧,永远处理最新画面,播放依旧保持高 FPS
推理不抢占全部 CPUFFmpeg 解码器设置线程数,预留 CPU 资源给 AI 推理
避免画面闪烁消失保留上一次检测结果,直到新推理结果到达,不会因为推理间隔导致检测框瞬间消失
本地文件无时间漂移使用QElapsedTimer累计时间,解码速度快于文件帧率时主动 sleep 补齐时间
渲染轻量化没有新检测结果直接显示原图,只有检测更新时才复制图像绘制框

核心思想:播放和检测解耦,画面优先,检测尽力而为。

八、项目亮点 & 踩坑记录

8.1 亮点

  1. QImage 与 cv::Mat 零拷贝包装:直接复用 QImage 内存构造 cv::Mat,仅 resize 推理输入时才发生内存拷贝,降低 CPU 内存开销。
  2. 有界队列丢弃旧帧:队列满丢掉最老帧,只保留最新画面,杜绝实时流延迟持续上涨,是视频 AI 工程非常关键的设计。
  3. 断流指数退避重连:重试间隔 1s→2s→4s,最大 30s 封顶;sleep 支持中断,关闭播放器时可以立刻退出线程,不会卡死等待 sleep 结束。
  4. FFmpeg 低延迟拉流参数:nobuffer、low_delay、rtsp‑transport=tcp,实现网络流秒开,降低缓冲延迟。
  5. 本地视频帧率对齐:不倍速飞速播放,按照源视频时间轴播放。
  6. 完整可观测指标:同时展示解码 FPS、检测 FPS、推理耗时,方便定位性能瓶颈;区分 “没有目标” 和 “还没有执行推理” 两种状态。
  7. 线程安全处理:自定义结构体Detection做元类型注册;Detector 明确非线程安全,只在检测线程串行调用;FFmpeg 资源统一释放出口。

8.2 踩坑记录

  1. YOLO ONNX 输出维度顺序坑YOLOv5 导出 ONNX 存在两种 shape:[1,25200,85]与[1,85,25200]。如果转置逻辑写反,现象很隐蔽:推理耗时正常,但是完全输出不到检测框。需要代码做 shape 自动判断与归一化。
  2. 检测框闪烁消失问题解码 30FPS,推理只有 4FPS,如果推理结果一完成就清空旧结果,检测框只会闪现几十毫秒肉眼几乎看不见。解决方案:保留上一轮检测结果,直到新结果到来才更新。
  3. BGR/RGB 通道顺序问题FFmpeg sws 输出 RGB24,YOLOv5 训练输入是 RGB,调用blobFromImage时swapRB=false;如果换成 OpenCV VideoCapture 读取,输出 BGR,此时必须开启 swapRB,否则推理效果完全报废。
  4. 跨线程传递自定义结构体QVector<Detection>跨线程信号槽,头文件Q_DECLARE_METATYPE(Detection),main 函数执行qRegisterMetaType<QVector<Detection>>(),否则 Qt 队列信号槽直接失效。
  5. 模型修复下载的yolov5s.onnx 是 opset 17 + FP16 导出的,OpenCV 4.5.5 DNN 不兼容。

    写转换脚本 fix_all.py做了三类图变换:FP16→FP32(权重 + Constant 节点)、Split→Slice(OpenCV 只支持等分切分)、axes 输入转 attribute。

九、后续升级扩展方向

9.1 性能优化

  1. GPU 推理:OpenCV DNN 切换DNN_BACKEND_CUDA,推理耗时可以从 160ms 下降至 10‑20ms;需要自行编译带 CUDA 支持的 OpenCV。
  2. 更换推理引擎:ONNX Runtime / TensorRT,加载 fp16 模型进一步提速。
  3. 调整推理输入尺寸:640→416/320,牺牲小目标检测换取速度;或者更换轻量模型 YOLOv5n / YOLOv8n / YOLO11n。
  4. 硬件解码:FFmpeg 开启 cuvid/qsv/d3d11va 硬件解码,降低 CPU 占用。

9.2 新增功能

  1. 目标追踪:接入 ByteTrack/SORT,给目标分配稳定 ID,消除检测框跳动,解决推理间隔带来的画面错位。
  2. 周界告警:越线检测、区域入侵检测,弹窗 / 声音报警。
  3. 截图与录像:检测触发自动保存图片 / 片段。
  4. 结果上报:检测结果输出 JSON/CSV 日志,WebSocket 推送给后端服务。
  5. 多路视频:多解码线程 + 检测线程池,网格布局多路摄像头同时检测。

9.3 UI 交互

  1. 参数配置面板:置信度阈值、NMS 阈值、检测抽帧间隔、类别过滤。
  2. 检测框插值平滑,推理间隔内做位置线性插值,消除画面卡顿感。

十、小结

本项目完整落地了一个Qt 视频 AI 播放器,把 FFmpeg 解码、多线程架构、背压丢帧、异常重连、OpenCV‑DNN 推理全部整合。

🔗Gitee 源码地址:先空下(...)

标签:QtFFmpegOpenCVYOLOv5ONNXRTSPRTMP多线程DNN视频目标检测

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/1 2:57:46

15 Pro 能用、15 不能用:Siri AI 划了三档

iOS 27 推送的同时&#xff0c;苹果公布了 Siri AI 支持名单。名单里最扎眼的不是谁在&#xff0c;而是谁不在&#xff1a;iPhone 15 Pro 能用&#xff0c;iPhone 15 不能用&#xff1b;iPad 要 M1 起步&#xff1b;完整语音功能还得单独跨过一道「统一内存不少于 12GB」的线。…

作者头像 李华
网站建设 2026/10/1 2:57:32

线上线下近3000人参与!FDE Open Night 在静安共话前线工程与交付落地

从技术走进业务现场&#xff0c;从需求走向实际交付。 9月23日晚&#xff0c;FDE Open Night 前线工程与交付落地交流会在上海静投中心举行。开发者、企业从业者与AI实践者相聚静安&#xff0c;围绕前线工程与交付落地&#xff0c;分享经验、交流问题。 活动由静安区科技和经…

作者头像 李华
网站建设 2026/10/1 2:57:17

盛水最多的容器与快乐数

三、盛水最多的容器给定一个长度为 n 的整数数组 height 。有 n 条垂线&#xff0c;第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。找出其中的两条线&#xff0c;使得它们与 x 轴共同构成的容器可以容纳最多的水。返回容器可以储存的最大水量。说明&#xff1a;你不能倾斜…

作者头像 李华
网站建设 2026/10/1 2:57:12

无传感器永磁同步电机零速控制:高频注入估算转子位置全解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/1 2:56:58

k8s的弹性伸缩

k8s弹性伸缩 自动扩缩容HPA 要实现扩缩容得先安装Metrics Server服务&#xff0c;因为自动扩缩容是通过监控容器得cpu或者memory得上限来实现弹性伸缩的&#xff0c;在 Kubernetes 集群中&#xff0c;Metrics Server 是一个用于收集和聚合集群内部组件的性能指标数据的服务。它…

作者头像 李华
网站建设 2026/10/1 2:55:45

RoPE 旋转位置编码

RoPE 旋转位置编码RoPE (旋转位置编码)流程step0 计算转速step1 算每个 token 的旋转角step2 求 cos / sinstep3 用 cos / sin 旋转 token&#xff08;作用到 Q 和 K&#xff09;总结RoPE (旋转位置编码) 流程 step0 计算转速 对于每个token xixixi,转速θ为[θ0,&#xff0…

作者头像 李华