Qt+OpenCV读取摄像头视频、本地视频、网络视频流Demo

Qt+OpenCV读取摄像头视频、本地视频、网络视频流Demo📹

更多精彩内容
👉个人内容分类汇总 👈

1、准备工作🎥

  • 看这里,下载官方编译的版本就可以了;

2、说明📺

  • 我写这个Demo的环境,但这个Demo不只局限于这个环境

    • 系统:Windows10
    • Qt版本:V5.12.5
    • OpenCV:opencv-4.6.0-vc14_vc15.exe(注意如果自己编译则要包含ffmpeg,否则部分功能不能使用)
    • 编译器:MSVC2017-64
  • Demo功能描述

    1. 启动时获取所有可用摄像头名称;
    2. 支持使用opencv打开本地摄像头,读取视频并显示;
    3. 由于opencv包含ffmpeg,所以支持打开多种格式的本地视频文件并显示;
    4. 支持打开多种协议的网络视频流并显示;
    5. 支持传入显示QImage、QPixmap图片进行显示;
    6. 支持图片的自适应窗口缩放,并保持纵横比。

3、关键代码🔍

  • VideoPlay.pro
# opencv需要带有ffmpeg才可以打开本地视频或者网络视频流,否则只能打开图片和摄像头
win32:CONFIG(release, debug|release): LIBS += -LE:/lib/opencv_MSVC2/build/x64/vc15/lib/ -lopencv_world460
else:win32:CONFIG(debug, debug|release): LIBS += -LE:/lib/opencv_MSVC2/build/x64/vc15/lib/ -lopencv_world460d
INCLUDEPATH += E:/lib/opencv_MSVC2/build/include
DEPENDPATH += E:/lib/opencv_MSVC2/build/include
  • videodisplay.h
#ifndef VIDEODISPLAY_H
#define VIDEODISPLAY_H

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

using namespace cv;

namespace Ui {
class VideoDisplay;
}

class VideoDisplay : public QWidget
{
    Q_OBJECT

public:
    explicit VideoDisplay(QWidget *parent = nullptr);
    ~VideoDisplay();

signals:
    void updateImage(QImage img);

private slots:
    void on_but_open_clicked();
    void readImage();
    void quitThread();
    QImage MatToQImage(const Mat& mat);

    void on_but_play_clicked();

    void on_but_file_clicked();

private:
    Ui::VideoDisplay *ui;

    VideoCapture* m_cap = nullptr;
    Mat mat;
    bool m_play = false;
};

#endif // VIDEODISPLAY_H

  • videodisplay.cpp
#include "videodisplay.h"
#include "ui_videodisplay.h"
#include <QtConcurrent>
#include <QCameraInfo>
#include <QFileDialog>

VideoDisplay::VideoDisplay(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::VideoDisplay)
{
    ui->setupUi(this);


    QList<QCameraInfo> cameras = QCameraInfo::availableCameras();   // 获取可用摄像头列表
    for(auto camera : cameras)
    {
        ui->com_cameras->addItem(camera.description());
    }

    m_cap = new VideoCapture();
    connect(this, &VideoDisplay::updateImage, ui->playImage, &PlayImage::updateImage);
}

VideoDisplay::~VideoDisplay()
{
    // 关闭并释放摄像头
    if(m_cap)
    {
        if(m_cap->isOpened())
        {
            quitThread();
        }
        delete m_cap;
    }
    delete ui;
}

/**
 * @brief 打开关闭摄像头
 */
void VideoDisplay::on_but_open_clicked()
{
    if(!m_cap->isOpened())
    {
        if(ui->com_cameras->count() <= 0) return;

        bool ret = m_cap->open(ui->com_cameras->currentIndex());
        if(ret)
        {
            m_play = true;
            ui->but_open->setText("关闭摄像头");
            QtConcurrent::run(this, &VideoDisplay::readImage);   // 在线程中读取
        }
    }
    else
    {
        quitThread();
        m_cap->release();
        ui->but_open->setText("打开摄像头");
    }
}

/**
 * @brief 打开本地视频或者网络视流,如rtsp、rtmp
 */
void VideoDisplay::on_but_play_clicked()
{
    if(!m_cap->isOpened())
    {
        QString url = ui->line_url->text();
        if(url.isEmpty()) return;
        bool ret = m_cap->open(url.toStdString());
        if(ret)
        {
            m_play = true;
            ui->but_play->setText("停止播放");
            QtConcurrent::run(this, &VideoDisplay::readImage);   // 在线程中读取
        }
    }
    else
    {
        quitThread();
        m_cap->release();
        ui->but_play->setText("开始播放");
    }
}

void VideoDisplay::on_but_file_clicked()
{
    QString str = QFileDialog::getOpenFileName(this, "视频文件", "./", "视频文件(*)");
    if(str.isNull()) return;

    ui->line_url->setText(str);
}

/**
 * @brief 退出opencv读取线程
 *        在一个线程打开关闭m_cap,在另一个线程异步读取需要先退出线程再关闭m_cap,否则可能导致m_cap关闭后又读取导致报错
 */
void VideoDisplay::quitThread()
{
    m_play = false;
    while (!m_play) {
        QThread::msleep(1);           // 等待线程退出
    }
    m_play = false;
}

/**
 * @brief 在线程中使用opencv读取图像
 */
void VideoDisplay::readImage()
{
    while (m_play && m_cap->isOpened())
    {
        bool ret = m_cap->read(mat);
        if(ret)
        {
            emit this->updateImage(MatToQImage(mat));   // 将mat转换为Qimage并发送给显示界面
        }

        QThread::msleep(1);           // 防止频繁读取或者读取不到
    }
    m_play = true;
}

/**
 * @brief       Mat转QImage
 * @param mat
 * @return
 */
QImage VideoDisplay::MatToQImage(const Mat &mat)
{
    switch (mat.type())
    {
    case CV_8UC1:
        {
            QImage img(mat.data, mat.cols, mat.rows, mat.cols, QImage::Format_Grayscale8);
            return img;
        }
    case CV_8UC3:
        {
            QImage img(mat.data, mat.cols, mat.rows, mat.cols * 3, QImage::Format_RGB888);
            return img.rgbSwapped();
        }
    case CV_8UC4:
        {
            QImage img(mat.data, mat.cols, mat.rows, mat.cols * 4, QImage::Format_ARGB32);
            return img;
        }
    default:
        {
            return QImage();
        }
    }
}


4、注意事项🔎

  • 如果opencv没有配置环境变量,则这个程序编译后无法运行;
  • 需要将opencv存放路径E:\lib\OpenCV_MSVC2\build\x64\vc15\bin路径下的opencv_videoio_ffmpeg460_64.dllopencv_videoio_msmf460_64.dllopencv_world460.dll三个文件拷贝到编译生成的可执行文件路径下;
  • 注意: 低版本的opencv没有opencv_videoio_msmf460_64.dll这个文件。

5、实现效果

在这里插入图片描述

6、完整源代码💻

💡💡💡💡💡💡💡💡💡💡💡💡💡💡

  • 8
    点赞
  • 82
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
如果你想在Qt读取地方摄像头视频,可以使用OpenCV的`VideoCapture`类进行操作。 具体步骤如下: 1. 在Qt中添加OpenCV库,可以在.pro文件中添加以下内容: ``` INCLUDEPATH += /usr/local/include/opencv4 LIBS += -L/usr/local/lib -lopencv_core -lopencv_highgui -lopencv_videoio ``` 其中,`/usr/local/include/opencv4`为OpenCV的头文件路径,`/usr/local/lib`为OpenCV库文件路径。 2. 在Qt中创建一个窗口用于显示视频。 3. 使用`VideoCapture`类打开地方摄像头,可以通过参数指定摄像头的设备编号或者视频文件的路径。 4. 循环读取视频帧并在窗口中显示,直到读取失败或者用户退出程序。 完整代码示例如下: ``` #include <opencv2/opencv.hpp> #include <QApplication> #include <QMainWindow> #include <QImage> #include <QPixmap> #include <QLabel> int main(int argc, char *argv[]) { QApplication app(argc, argv); QMainWindow window; QLabel label; window.setCentralWidget(&label); window.show(); cv::VideoCapture cap(0); // 打开地方摄像头 if (!cap.isOpened()) // 打开失败 { std::cerr << "Failed to open camera." << std::endl; return -1; } while (true) // 循环读取视频帧 { cv::Mat frame; cap >> frame; // 读取视频帧 if (frame.empty()) break; // 读取失败,退出循环 cv::cvtColor(frame, frame, cv::COLOR_BGR2RGB); // OpenCV图像格式为BGR,需要转换为RGB QImage qimg(frame.data, frame.cols, frame.rows, QImage::Format_RGB888); // 创建QImage对象 QPixmap qpixmap = QPixmap::fromImage(qimg); // 转换为QPixmap对象 label.setPixmap(qpixmap); // 显示在窗口中 QApplication::processEvents(); // 处理Qt事件,保证窗口正常显示 if (cv::waitKey(30) == 'q') break; // 按下q键退出循环 } return app.exec(); } ``` 其中,`QMainWindow`和`QLabel`用于创建窗口和显示视频帧,`QImage`和`QPixmap`用于将OpenCV的图像格式转换为Qt的图像格式,`QApplication::processEvents()`用于保证窗口正常显示。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mahuifa

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值