海康摄像机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️⃣ 锁优化

  • DecodeCallbackVideoWidget::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 响应更流畅
相关推荐
yolo_guo4 小时前
opencv 学习: QA_01 什么是图像锐化
linux·c++·opencv·计算机视觉
CS创新实验室1 天前
OpenCV:从经典到现代,计算机视觉的基石与未来
人工智能·opencv·计算机视觉·cv
XXYBMOOO1 天前
探索图像处理中的九种滤波器:从模糊到锐化与边缘检测
图像处理·人工智能·python·opencv·计算机视觉
胖墩会武术1 天前
【OpenCV图像处理】图像去噪:cv.fastNlMeansDenoising()
图像处理·opencv·计算机视觉
Valueyou241 天前
论文阅读——CenterNet
论文阅读·python·opencv·目标检测·计算机视觉
hixiong1232 天前
C# OpenCVSharp实现Hand Pose Estimation Mediapipe
开发语言·opencv·ai·c#·手势识别
Dm_dotnet2 天前
OpenCVSharp:ArUco 标记检测与透视变换
opencv
yy_xzz2 天前
OpenCV 图像处理与键盘交互
图像处理·opencv
却道天凉_好个秋2 天前
OpenCV(二十四):图像滤波
人工智能·opencv·计算机视觉