欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

用QThread及QObject的movetothread两种多线程方法实现在QT控件上播放opencv视频

程序员文章站 2022-05-10 12:10:05
...

 视频截图如下

用QThread及QObject的movetothread两种多线程方法实现在QT控件上播放opencv视频

用QThread及QObject的movetothread两种多线程方法实现在QT控件上播放opencv视频

使用一个单独的线程处理和显示视频源的输入帧和输出帧,有助于使GUI线程(主线程)保持空闲及可响应性,而用第二线程处理更密集的进程。

准备工作:

创建含两个label的QT控件应用程序,并在.pro文件中配置opencv:

INCLUDEPATH += /usr/local/include \
               /usr/local/include/opencv \
               /usr/local/include/opencv2

LIBS += /usr/local/lib64/libopencv*

第一种方法(官方已不推荐的老方法):子类化QThread。 思路如下:

一,创建类继承Qthread:       class videoProcessorThread : public QThread

重写run函数,作为新线程入口。run函数中1打开视频,2设定时时器延时读取视频帧,3给主框架发送显示帧图片消息,4加上this->exec();支持信号槽。

二,主框架MainWindow的构造函数中,1建立显示图片的信号槽连接,2启动线程。析构函数中3结束线程。

代码如下:

videoprocessorthread.h

#ifndef VIDEOPROCESSORTHREAD_H
#define VIDEOPROCESSORTHREAD_H

#include <QObject>
#include <QThread>
#include <QPixmap>
#include <opencv2/opencv.hpp>
using namespace cv;


class videoProcessorThread : public QThread
{
    Q_OBJECT
public:
    explicit videoProcessorThread(QObject *parent = nullptr);
    void showCamera();
    void stopVideo();

signals:
    void inDisplay(QPixmap pixmap);
    void outDisplay(QPixmap pixmap);

public slots:
private:
    void run() override;
    VideoCapture camera;
    Mat inFrame,outFrame;
    QTimer *timer;
};

#endif // VIDEOPROCESSORTHREAD_H

videoprocessorthread.cpp

 

#include "videoprocessorthread.h"
#include <QDebug>
#include "QTimer"

videoProcessorThread::videoProcessorThread(QObject *parent) : QThread(parent)
{

}

void videoProcessorThread::run()
{
    camera = VideoCapture("/home/jello/myprojects/images/bike.avi");

    double rate = camera.get(CV_CAP_PROP_FPS);
    int delay = 1000/rate;
    timer = new QTimer();
    connect(timer,&QTimer::timeout,this,&videoProcessorThread::showCamera);
    if(camera.isOpened())
    {
    timer->start(delay);
    this->exec();
    }
}

void videoProcessorThread::showCamera()
{
    camera >> inFrame;
    bitwise_not(inFrame, outFrame);

    emit inDisplay(
                QPixmap::fromImage(
                    QImage(
                        inFrame.data,
                        inFrame.cols,
                        inFrame.rows,
                        inFrame.step,
                        QImage::Format_RGB888)
                    .rgbSwapped()));
    emit outDisplay(QPixmap::fromImage(
                        QImage(
                            outFrame.data,
                            outFrame.cols,
                            outFrame.rows,
                            outFrame.step,
                            QImage::Format_RGB888)));
}

void videoProcessorThread::stopVideo()
{
    timer->stop();
    delete timer;
}
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "videoprocessorthread.h"

#include "videoprocessor.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

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

protected:
    void closeEvent(QCloseEvent *event);

private:
    Ui::MainWindow *ui;
    videoProcessorThread processor;

//    VideoProcessor *processor1;
};

#endif // MAINWINDOW_H
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QCloseEvent>

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

    connect(&processor,
            SIGNAL(inDisplay(QPixmap)),
            ui->inVideo,
            SLOT(setPixmap(QPixmap)));

    connect(&processor,
            SIGNAL(outDisplay(QPixmap)),
            ui->outVideo,
            SLOT(setPixmap(QPixmap)));

    processor.start();

}

void MainWindow::closeEvent(QCloseEvent *event)
{
    processor.stopVideo();
    processor.quit();
    processor.wait();

    event->accept();
}

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

第二种方法:movetothread

线程处理类直接继承QObject

#ifndef VIDEOPROCESSOR_H
#define VIDEOPROCESSOR_H

#include <QObject>
#include <QPixmap>
#include "opencv2/opencv.hpp"
using namespace cv;

class VideoProcessor : public QObject
{
    Q_OBJECT
public:
    explicit VideoProcessor(QObject *parent = nullptr);
    void showCamera();

signals:
    void inDisplay(QPixmap pixmap);
    void outDisplay(QPixmap pixmap);

public slots:
    void startVideo();
    void stopVideo();

private:
    bool stopped;
    VideoCapture camera;
    Mat inFrame, outFrame;
    QTimer *timer;
};

#endif // VIDEOPROCESSOR_H

构造函数中没有分配任何父函数,有父对象的对象不能移动到新的线程中。

#include "videoprocessor.h"
#include <QTimer>

VideoProcessor::VideoProcessor(QObject *parent) : QObject(parent)
{

}

void VideoProcessor::startVideo()
{
    camera = VideoCapture("/home/jello/myprojects/images/bike.avi");
    stopped = false;

    double rate = camera.get(CV_CAP_PROP_FPS);
    int delay = 1000/rate;
    timer = new QTimer();
    connect(timer,&QTimer::timeout,this,&VideoProcessor::showCamera);

    if(camera.isOpened())
        timer->start(delay);
}

void VideoProcessor::showCamera()
{
    camera >> inFrame;
    bitwise_not(inFrame, outFrame);

    emit inDisplay(QPixmap::fromImage(
                       QImage(
                           inFrame.data,
                           inFrame.cols,
                           inFrame.rows,
                           inFrame.step,
                           QImage::Format_RGB888)));
    emit outDisplay(QPixmap::fromImage(
                        QImage(
                            outFrame.data,
                            outFrame.cols,
                            outFrame.rows,
                            outFrame.step,
                            QImage::Format_RGB888)));
}

void VideoProcessor::stopVideo()
{
    timer->stop();
    delete timer;
}

主框架中创建VideoProcessor的实例,并定义为指针。

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

#include "videoprocessor.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

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

private:
    Ui::MainWindow *ui;

    VideoProcessor *processor1;
};

#endif // MAINWINDOW_H

不应该直接调用VideoProcessor的startVideo函数,而应该将一个适合的信号连接到它进行调用。线程结束信号连接到deleteLater槽函数。

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

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

    processor1 = new VideoProcessor();
    processor1->moveToThread(new QThread(this));

    connect(processor1->thread(),SIGNAL(started()),processor1,SLOT(startVideo()));
    connect(processor1->thread(),SIGNAL(finnished()),processor1,SLOT(deleteLater()));
    connect(processor1,SIGNAL(inDisplay(QPixmap)),ui->inVideo,SLOT(setPixmap(QPixmap)));
    connect(processor1,SIGNAL(outDisplay(QPixmap)),ui->outVideo,SLOT(setPixmap(QPixmap)));

    processor1->thread()->start();
}

MainWindow::~MainWindow()
{
    processor1->stopVideo();
    processor1->thread()->quit();
    processor1->thread()->wait();

    delete ui;
}

 

相关标签: C++ opencv linux