如何在Qt5 C++ Widget中显示OpenCV读取的视频帧?
在Qt Widget中显示OpenCV读取的视频帧
嘿,我刚好做过类似的需求,给你一个完整的可运行示例,直接把OpenCV读取的视频帧显示在Qt的自定义Widget里,步骤清晰,你可以直接套用:
核心思路
要实现这个功能,关键是完成两个核心步骤:
- 把OpenCV的
cv::Mat格式帧转换成Qt能识别的QImage格式 - 在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); }
关键注意事项
- 项目配置:在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 - 格式转换:一定要注意OpenCV和Qt的颜色通道顺序差异(BGR vs RGB),不然图像颜色会错乱。
- 性能优化:如果视频分辨率很高,可以考虑在转换前先缩小帧的尺寸,避免绘制时卡顿。
内容的提问来源于stack exchange,提问作者Davtag
相关产品推荐
相关产品推荐

