使用 Qt+opencv 播放视频 从while(1) waitKey 到 timerevent的演进

使用 while 循环结合waitKey和使用 Qt 的 QTimerEvent进行定时任务处理,在GUI应用程序中是两种截然不同的方法。

while循环结合 waitKey

原理:


这种方法通常用于简单的CV应用,特别是在不涉及复杂UI界面的情况下。while 循环连续读取视频帧,waitKey 函数用于捕获键盘输入,并允许一定程度的UI响应性,相当于在帧中间的延迟。

缺点:


阻塞UI:

在GUI应用中,如果使用 while 循环,尤其是在Qt的主线程中运行,会阻塞事件循环,有可能导致UI无响应或延迟响应用户操作。


CPU资源消耗:

持续运行的 while 循环可能导致CPU使用率较高,尤其是循环体内延迟较低时。
 

QTimerEvent

原理:


信号与槽机制,事件通知机制

优点:


非阻塞:

使用 QTimer 不会阻塞Qt的事件循环,保持应用的响应性和流畅性。


资源高效:

定时器仅在指定的时间间隔激活,可以更有效地管理CPU资源,降低CPU使用率。

下面是一个无bug+考虑了大多数边缘情况的while(1)+waitKey的代码实现

界面:

一个button + 一个label

main.cpp

#include "mainwindow.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QDebug>
#include <QMainWindow>
#include <QPixmap>
#include <opencv.hpp>
#include <QMessageBox>
using namespace cv;
QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void on_pushButton_clicked();

private:
    Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

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

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_pushButton_clicked()
{
    VideoCapture vc;

    if (!vc.open(0)) {
        QMessageBox::warning(this, "open failed !", "open failed !");
        return;
    }
    Mat frame;
    while (1) {
        vc.read(frame);
        if (frame.empty()) {
            break;
        }
        rectangle(frame,
                  Rect(frame.cols / 2 - 100, frame.rows / 2 - 100, 200, 200),
                  Scalar(0, 0, 255));
        cvtColor(frame, frame, COLOR_BGR2RGB);
        QImage image(frame.data, frame.cols, frame.rows, frame.step, QImage::Format_RGB888);
        ui->label->setPixmap(QPixmap(QPixmap::fromImage(image)));
        waitKey(1);
         
    }
    vc.release();
    destroyAllWindows();
}

 改成Qtimerevent:

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QDebug>
#include <QMainWindow>
#include <QMessageBox>
#include <QPixmap>
#include <QTimerEvent>
#include <opencv.hpp>
using namespace cv;
QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void on_pushButton_clicked();

private:
    Ui::MainWindow *ui;
    VideoCapture vc;
    int timerId;

    // QObject interface
protected:
    void timerEvent(QTimerEvent *event);
};
#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    if (!vc.open(0)) {
        QMessageBox::warning(this, "open failed !", "open failed !");
        return;
    }
    timerId = startTimer(33);
}

MainWindow::~MainWindow()
{
    if (vc.isOpened()) {
        vc.release();
    }
    delete ui;
}

void MainWindow::on_pushButton_clicked() {}

void MainWindow::timerEvent(QTimerEvent *event)
{
    //区分多个计时器
    if (event->timerId() == timerId) {
        Mat frame;
        vc.read(frame);
        if (frame.empty()) {
            QMessageBox::warning(this, "no signals !", "no signals !");
            return;
        }
        rectangle(frame,
                  Rect(frame.cols / 2 - 100, frame.rows / 2 - 100, 200, 200),
                  Scalar(0, 0, 255));
        cvtColor(frame, frame, COLOR_BGR2RGB);
        QImage image(frame.data, frame.cols, frame.rows, frame.step, QImage::Format_RGB888);
        ui->label->setPixmap(QPixmap::fromImage(image));
    }
}

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值