网站菜单

QT开发心得——使用QThread创建多线程

为什么要使用多线程

最常见的情况是,我需要使用一个子线程处理一个子任务,然后将子任务的运行结果显示在主线程MainWindow上。若只使用主线程进行计算,那么在运行这个子任务的时候,MainWindow的其他任务是无法运行的。如果我想一个Mainwindow同时显示两个摄像头,是无法完成的。又或者是子任务需要等待一段时间(sleep等),MainWindow便会无响应。

跟C++11中很像的是,Qt中使用QThread来管理线程,一个QThread对象管理一个线程,在使用上有很多跟C++11中相似的地方,但更多的是Qt中独有的内容。另外,QThread对象也有消息循环exec()函数,即每个线程都有一个消息循环,用来处理自己这个线程的事件。

废话不多说,直接用一个开发样例进行讲解。

任务目的

使用QThread在子线程使用opencv采集摄像头,并在MainWindow实时显示。

基本思路

  1. 在主线程设置一个触发器,触发以后运行子线程
  2. 子线程调用OpenCV采集摄像头,将采集的Mat转化成QImage
  3. 主线程发现采集到了QImage,更新主线程的UI

伪代码

//主线程
//第一步,在主线程设置一个触发器,触发以后运行子线程
connect(操作界面上的按钮,按钮抬起,this,触发子线程的方法);

//第二步,子线程调用OpenCV采集摄像头,将采集的Mat转化成QImage
子线程 = new 子线程(this);

//第三步,主线程发现采集到的了QImage,更新主线程的UI
connect(子线程,SIGNAL(获取到了QImage), this,SLOT(更新UI的方法));
//子线程
void 子线程名::run()     //overwrite
{
    永远
    {
        摄像头开关为true:采集();
        摄像头开关为false:,将开关设置为true然后break;
    }
}

void 子线程名::采集()
{
    如果没有检测到摄像头:摄像头开关设置为false,回收资源
    如果检测到摄像头:采集到Mat里,转化为QImage,提醒主线程采集到QImage了
}

注意事项

子线程:

使用emit()来提醒主线程获取到了新的资源。emit函数调用的方法应声明在.h头函数的signals分类中。

主线程:

注意线程的调用以及回收。

关键部分代码:

mainwindow.cpp

//left camera stream thread
connect(ui->pushButton_leftStream, &QPushButton::released, this, &MainWindow::on_pushButton_leftStream_released);
left_thread = new LeftCameraThread(this);
connect(left_thread, SIGNAL(captured(QImage)), this, SLOT(updateLeftGraphics()));



//capture current stream----left
void MainWindow::on_pushButton_leftStream_released()
{
    left_thread->start();
}


//update graphicsViewLeft
void MainWindow::updateLeftGraphics()
{
    QGraphicsScene *leftScene = new QGraphicsScene;
    leftScene->addPixmap(QPixmap::fromImage(leftDiskImage).scaled(645,381, Qt::KeepAspectRatio));
    ui->graphicsViewLeft->setScene(leftScene);
    ui->graphicsViewLeft->show();
}

leftCameraThread.cpp

#include "LeftCameraThread.h"
#include "mainwindow.h"
#include <opencv2/opencv.hpp>
#include <opencv2/videoio.hpp>
#include <iostream>
#include <QGraphicsScene>

using namespace cv;
using namespace std;

//SDK
extern bool             leftCamSwitch;
extern Mat              leftFrame;
extern QImage           leftDiskImage;

VideoCapture capture0(0);

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

}

void LeftCameraThread::run()
{
    forever
    {
        if(leftCamSwitch)      //default is on
        {
            LeftCameraThread::captureProcess();
        }
        else                   //or off
        {
            leftCamSwitch = true;
            break;
        }
    }
}

void LeftCameraThread::captureProcess()
{
    if (!capture0.isOpened())        //if no camera connection
    {
        cout << "No video stream detected" << endl;
        capture0.release();
        leftCamSwitch = false;
    }
    else
    {
        capture0 >> leftFrame;
        cvtColor(leftFrame, leftFrame, COLOR_BGR2RGB);
        leftDiskImage = QImage((const unsigned char*)leftFrame.data, leftFrame.cols, leftFrame.rows, leftFrame.step,QImage::Format_RGB888);
        emit captured(leftDiskImage);
    }
}

leftCamera.h

#ifndef PALLETIZINGCAMERA_LEFTCAMERATHREAD_H
#define PALLETIZINGCAMERA_LEFTCAMERATHREAD_H

#include <QThread>
#include <QImage>
#include <QObject>
#include <QDebug>


class LeftCameraThread : public QThread
{
    Q_OBJECT
public:
    explicit LeftCameraThread(QObject *parent = 0);

public:
    void run();
    void captureProcess();

signals:
    void captured(QImage image);

public slots:

private:

};


#endif //PALLETIZINGCAMERA_LEFTCAMERATHREAD_H
显示评论 (0)

文章评论

相关推荐

Ubuntu交叉编译Python

在 Ubuntu 上交叉编译 Python 的流程通常用于为不同平台生成可执行文件(如 ARM、MIPS 等)。以下是一般的操作步骤: 1. 安装必要的依赖工具 首先,确保已经安装了编译所需的工具和依…

RKNN开发环境常用命令

板端 确认RKNPU2驱动版本 检查RKNPU2环境是否安装 如果出现以下信息则代表启动服务成功 检查版本是否一致 如果出现以下输出,则代表有rknn环境 安装RKNN服务 查看NPU占用

此文章禁止复制~