You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Qt5 C++ Widget中显示OpenCV读取的视频帧?

在Qt Widget中显示OpenCV读取的视频帧

嘿,我刚好做过类似的需求,给你一个完整的可运行示例,直接把OpenCV读取的视频帧显示在Qt的自定义Widget里,步骤清晰,你可以直接套用:

核心思路

要实现这个功能,关键是完成两个核心步骤:

  1. 把OpenCV的cv::Mat格式帧转换成Qt能识别的QImage格式
  2. 在Qt Widget的paintEvent中绘制转换后的图像,并用定时器定时读取新帧更新显示

完整示例代码

1. 自定义视频显示Widget的头文件(VideoDisplayWidget.h)

#ifndef VIDEODISPLAYWIDGET_H
#define VIDEODISPLAYWIDGET_H

#include <QWidget>
#include <QTimer>
#include <opencv2/opencv.hpp>

class VideoDisplayWidget : public QWidget
{
    Q_OBJECT
public:
    explicit VideoDisplayWidget(QWidget *parent = nullptr);
    ~VideoDisplayWidget();

    // 设置视频文件路径
    void setVideoSource(const QString &videoPath);
    // 设置摄像头索引(0通常是默认摄像头)
    void setCameraSource(int cameraIndex);

protected:
    void paintEvent(QPaintEvent *event) override;

private slots:
    void updateFrame();

private:
    cv::VideoCapture m_capture;
    cv::Mat m_currentFrame;
    QTimer *m_updateTimer;

    // 核心转换函数:OpenCV Mat → Qt QImage
    QImage matToQImage(const cv::Mat &mat);
};

#endif // VIDEODISPLAYWIDGET_H

2. 自定义Widget的源文件(VideoDisplayWidget.cpp)

#include "VideoDisplayWidget.h"
#include <QPainter>
#include <QDebug>

VideoDisplayWidget::VideoDisplayWidget(QWidget *parent) : QWidget(parent)
{
    m_updateTimer = new QTimer(this);
    // 定时器触发时更新视频帧
    connect(m_updateTimer, &QTimer::timeout, this, &VideoDisplayWidget::updateFrame);
}

VideoDisplayWidget::~VideoDisplayWidget()
{
    if (m_capture.isOpened()) {
        m_capture.release();
    }
}

void VideoDisplayWidget::setVideoSource(const QString &videoPath)
{
    if (m_capture.isOpened()) {
        m_capture.release();
    }
    // 打开本地视频文件
    m_capture.open(videoPath.toStdString());
    if (m_capture.isOpened()) {
        // 根据视频帧率设置定时器间隔
        int fps = m_capture.get(cv::CAP_PROP_FPS);
        m_updateTimer->start(1000 / fps);
    } else {
        qDebug() << "打开视频文件失败:" << videoPath;
    }
}

void VideoDisplayWidget::setCameraSource(int cameraIndex)
{
    if (m_capture.isOpened()) {
        m_capture.release();
    }
    // 打开摄像头
    m_capture.open(cameraIndex);
    if (m_capture.isOpened()) {
        // 摄像头默认按30帧/秒更新,间隔约33ms
        m_updateTimer->start(33);
    } else {
        qDebug() << "打开摄像头失败,索引:" << cameraIndex;
    }
}

void VideoDisplayWidget::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event);
    QPainter painter(this);
    
    if (!m_currentFrame.empty()) {
        // 转换Mat到QImage
        QImage image = matToQImage(m_currentFrame);
        // 缩放图像以适应Widget大小,保持比例
        QImage scaledImage = image.scaled(this->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
        // 居中绘制图像
        int x = (this->width() - scaledImage.width()) / 2;
        int y = (this->height() - scaledImage.height()) / 2;
        painter.drawImage(x, y, scaledImage);
    } else {
        // 没有帧时显示提示文字
        painter.drawText(rect(), Qt::AlignCenter, "无视频帧");
    }
}

void VideoDisplayWidget::updateFrame()
{
    if (m_capture.isOpened()) {
        cv::Mat frame;
        m_capture >> frame;
        if (!frame.empty()) {
            m_currentFrame = frame.clone();
            // 触发重绘更新显示
            update();
        } else {
            // 视频播放完毕,停止定时器
            m_updateTimer->stop();
            qDebug() << "视频播放结束";
        }
    }
}

QImage VideoDisplayWidget::matToQImage(const cv::Mat &mat)
{
    // 处理彩色图:OpenCV默认BGR格式,Qt是RGB,需要交换通道
    if (mat.type() == CV_8UC3) {
        QImage image(mat.data, mat.cols, mat.rows, mat.step, QImage::Format_RGB888);
        return image.rgbSwapped();
    } 
    // 处理灰度图
    else if (mat.type() == CV_8UC1) {
        return QImage(mat.data, mat.cols, mat.rows, mat.step, QImage::Format_Grayscale8);
    } 
    // 其他格式暂不支持,可根据需求扩展
    else {
        qDebug() << "不支持的Mat格式";
        return QImage();
    }
}

3. 在主窗口中使用这个Widget(MainWindow.cpp示例)

#include "MainWindow.h"
#include "VideoDisplayWidget.h"
#include <QVBoxLayout>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    VideoDisplayWidget *videoWidget = new VideoDisplayWidget(this);
    
    // 可选:播放本地视频
    // videoWidget->setVideoSource("你的视频文件路径.mp4");
    // 可选:打开摄像头(0为默认摄像头)
    videoWidget->setCameraSource(0);

    QWidget *centralWidget = new QWidget(this);
    QVBoxLayout *layout = new QVBoxLayout(centralWidget);
    layout->addWidget(videoWidget);
    setCentralWidget(centralWidget);
    
    setWindowTitle("OpenCV + Qt 视频显示");
    resize(800, 600);
}

关键注意事项

  1. 项目配置:在Qt的.pro文件中需要添加OpenCV的链接配置,比如:
    QT += core gui widgets
    # 如果你用pkg-config管理OpenCV
    LIBS += `pkg-config opencv4 --libs`
    INCLUDEPATH += `pkg-config opencv4 --cflags`
    # Windows环境可能需要手动指定路径,比如:
    # INCLUDEPATH += D:/opencv/include
    # LIBS += D:/opencv/lib/opencv_world455.lib
    
  2. 格式转换:一定要注意OpenCV和Qt的颜色通道顺序差异(BGR vs RGB),不然图像颜色会错乱。
  3. 性能优化:如果视频分辨率很高,可以考虑在转换前先缩小帧的尺寸,避免绘制时卡顿。

内容的提问来源于stack exchange,提问作者Davtag

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 16:35:13