海康摄像机SDK获取视频流转码显示

开发环境

vs2017+QT5.9+海康威视SDK+opencv

代码

该博主代码略加修改即可运行,存在问题:cpu占用率达50%;拖动窗口明显延迟

https://blog.csdn.net/2501_90502174/article/details/146361878?fromshare=blogdetail&sharetype=blogdetail&sharerId=146361878&sharerefer=PC&sharesource=weixin_44965579&sharefrom=from_linkhttps://blog.csdn.net/2501_90502174/article/details/146361878?fromshare=blogdetail&sharetype=blogdetail&sharerId=146361878&sharerefer=PC&sharesource=weixin_44965579&sharefrom=from_link

我的改动

SDK的导入由环境变量改为相对路径,即< >改为" "

Format_BGR888改为Format_RGB888,qt5不支持Format_BGR888

复制代码
// 13. 生成 QImage(Qt5兼容写法)
// 先将BGR转为RGB,再用Format_RGB888构造
        cv::Mat rgbMat;
        cv::cvtColor(bgrMat, rgbMat, cv::COLOR_BGR2RGB);
        QImage img(rgbMat.data, rgbMat.cols, rgbMat.rows, rgbMat.step, QImage::Format_RGB888);

gpt给的改进方案

一、项目数据流与线程分析

目前视频流处理流程是:

复制代码
HK SDK → RealDataCallback (SDK 内线程)
    ↓
PlayM4 解码 → DecodeCallback
    ↓
YUV → BGR → RGB → QImage
    ↓
emit frameUpdated (HikCamera 对象)
    ↓
CameraThread 捕获 newFrame
    ↓
emit newFrame → VideoWidget.updateFrame()
    ↓
paintEvent 绘制

特点:

  1. 多线程:

    • SDK 内部线程(RealDataCallback) → PlayM4 解码 → DecodeCallback

    • CameraThread 继承 QThread,接收 frameUpdated 并发 newFrame 信号

    • VideoWidget 在 GUI 线程绘制

  2. 瓶颈点:

    • DecodeCallback 每帧都进行 YUV→BGR→RGB → QImage → copy()

    • VideoWidget::updateFrame() 对 QImage 做了 scaled() + QPixmap::fromImage()

    • paintEvent 每次 update() 都重新绘制 QPixmap

    • 线程间通过信号传递每帧,Qt 信号默认是 QueuedConnection,每帧都进入事件队列

    • 对于高帧率(25~30fps)视频,可能导致 事件队列堆积 → CPU 占用高、UI 卡顿


二、主要性能问题分析

  1. CPU 占用高(50%)原因:

    • 每帧都做 两次颜色转换:

      复制代码
      cv::cvtColor(yuvMat, bgrMat, cv::COLOR_YUV2BGR_YV12);
      cv::cvtColor(bgrMat, rgbMat, cv::COLOR_BGR2RGB);
    • QImage img(rgbMat.data, ...) + img.copy() → 内存拷贝

    • VideoWidget::updateFrame 调用 scaled() → CPU 缩放

    • paintEvent 每次都重绘整个控件

  2. 拖动窗口卡顿原因:

    • paintEvent 重绘与 updateFrame 信号频率高

    • QWidget 使用 Qt::WA_OpaquePaintEvent,每次重绘全屏消耗 CPU

    • 图像缩放是同步的,阻塞 GUI 线程

  3. 线程安全与锁:

    • 每帧使用 QMutexLocker 对 m_currentFrame 上锁 → 如果锁等待时间过长,也可能拖慢 UI

三、优化方案

1️⃣ 减少颜色转换开销

  • 如果后续 YOLO 使用 OpenCV,可以保持 BGR 格式,不必转换为 RGB 再 QImage。

  • Qt 支持使用 QImage::Format_BGR888(Qt 5.9 支持较有限)或者直接绘制 OpenCV Mat:

    cv::Mat bgrMat; // 已解码的 BGR
    QImage img(bgrMat.data, bgrMat.cols, bgrMat.rows, bgrMat.step, QImage::Format_RGB888); // 不做 copy
    emit frameUpdated(img); // 去掉 copy()

  • 避免重复 cvtColor,如果不必显示 RGB,可直接用 BGR Mat 做后续处理(YOLO)。


2️⃣ 优化 VideoWidget 渲染

  • 避免每帧做 scaled(),只在 resizeEvent 时做一次缩放:

    void VideoWidget::updateFrame(const QImage& frame)
    {
    if (frame.isNull()) return;
    QMutexLocker locker(&m_mutex);
    m_currentFrame = QPixmap::fromImage(frame); // 不缩放
    update();
    }

    void VideoWidget::resizeEvent(QResizeEvent* event)
    {
    QMutexLocker locker(&m_mutex);
    if (!m_currentFrame.isNull())
    m_currentFrame = m_currentFrame.scaled(size(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
    QWidget::resizeEvent(event);
    }

  • paintEvent 中直接绘制 m_currentFrame,无需每帧缩放。

  • 或者使用 QLabel + setPixmap,Qt 内部优化比手动 scaled 快。


3️⃣ 降低信号队列压力

  • 使用 Qt::DirectConnection 或在 DecodeCallback 内部 限制帧率:

    static QElapsedTimer timer;
    static int fps = 30;
    if (timer.elapsed() < 1000 / fps) return;
    timer.restart();
    emit camera->frameUpdated(img);

  • 或者在 CameraThread 内做 帧丢弃策略,保证 GUI 线程只处理 20~30 fps 即可。


4️⃣ 异步 YOLO 推理

  • 不要在 GUI 线程做 YOLO 推理

  • 可以在 CameraThread 或单独的推理线程做:

    // CameraThread 收到 frameUpdated
    if (!m_inferThread->isRunning())
    m_inferThread->enqueueFrame(frame); // 推理线程队列

  • 推理线程输出结果 → GUI 线程绘制标注 → 显示


5️⃣ 锁优化

  • DecodeCallback 和 VideoWidget::updateFrame 使用的锁可以考虑:

    • 使用 QAtomicPointer / std::atomic 替代 QMutex,避免每帧锁等待

    • 或者使用 双缓冲,一帧在后台解码,一帧在前台绘制


6️⃣ 其他小优化

  1. QImage::copy() → 只在必须时做

  2. paintEvent 填充背景可以省略 fillRect,如果 WA_OpaquePaintEvent 与 QPixmap 覆盖

  3. HikCamera 初始化阶段尽量复用 PlayM4 端口,不必频繁获取释放


四、总体优化建议

优化点 方法 预期效果
YUV → RGB → QImage 避免多余转换,保持 BGR CPU 占用降低 10~20%
QImage → QPixmap 缩放 只在 resize 时缩放 UI 拖动卡顿明显改善
信号队列 限制帧率 20~30 fps CPU 占用下降,避免 GUI 阻塞
Mutex 双缓冲或原子指针 降低锁开销
YOLO 推理 单独线程异步处理 不阻塞 UI,保持视频流顺滑
paintEvent 避免每帧 full repaint UI 响应更流畅
相关推荐
晨间晓16 小时前
图片里的高频和低频是什么?用华为云码道开发 OpenCV 傅里叶频谱分析工具
opencv·计算机视觉·华为云
晨间晓16 小时前
图片里的阴影能不能减弱?用华为云码道开发 OpenCV 光照校正工具
人工智能·opencv·华为云
晨间晓1 天前
图片里的细小噪点怎么平滑?用华为云码道开发 OpenCV 图像滤波对比工具
人工智能·opencv·华为云
偷吃米饭1 天前
图片特征怎么描述?用华为云码道开发 OpenCV ORB 特征提取工具
人工智能·opencv·华为云
晨间晓2 天前
图片里的关键点怎么找?用华为云码道开发 OpenCV FAST 特征点检测工具
人工智能·opencv·华为云
晨间晓2 天前
二值图里的噪点怎么去掉?用华为云码道开发 OpenCV 形态学操作工具
人工智能·opencv·华为云
晨间晓2 天前
图片里的角点在哪里?用华为云码道开发 OpenCV Harris 角点检测工具
人工智能·opencv·华为云
晨间晓2 天前
图片细节丰富不丰富?用华为云码道开发 OpenCV 纹理复杂度分析工具
人工智能·opencv·华为云
richard_yuu2 天前
OpenCV 实战第 15 篇:G-API 图计算,工业流水线的 CPU/GPU 混合执行
人工智能·opencv·计算机视觉
老唐7773 天前
OpenCV5实测:纯CPU跑YOLO26目标检测
图像处理·人工智能·opencv·yolo·目标检测·计算机视觉