参考《OpenCV3与Qt5计算机视觉应用开发》
请参阅本人写的上一篇博客,使用 QThread 子类化创建多线程的方法
2 使用 moveToThread 函数创建多线程
2.1 创建应用程序和新类
按照同样的方法创建应用程序和新的 C++ 类,命名为 VideoProcessor。注意,该类创建后,不需要从 QThread 类继承,而是保留从QObject类继承。(具体参考本人前一篇博客)
2.2 头文件声明信号和槽
将以下成员添加到 videoprocessor.h 文件中:
包含文件:
#include <QObject>
#include <QPixmap>
#include <QDebug>
#include <QMutex>
#include <QReadWriteLock>
#include <QSemaphore>
#include <QWaitCondition>
#include "opencv2/opencv.hpp"
信号和槽:
signals:
void inDisplay(QPixmap pixmap);
void outDisplay(QPixmap pixmap);
public slots:
void startVideo();
void stopVideo();
private:
bool stopped;
代码解析: stopped 是标志符,用于帮助终止视频。声明的两个槽分别是用来启动和终止摄像头处理的。
2.3 修改代码
在 videoprocessor.cpp 文件中添加以下代码,这里不需要实现 run 函数,因为这不是 QThread 的子类:
void VideoProcessor::startVideo()
{
using namespace cv;
VideoCapture camera(0);
Mat inFrame, outFrame;
stopped = false;
while(camera.isOpened() && !stopped)
{
camera >> inFrame;
if(inFrame.empty())
continue;
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)
.rgbSwapped()));
}
}
void VideoProcessor::stopVideo()
{
qDebug() << Q_FUNC_INFO;
stopped = true;
}
将下列代码添加至 MainWindow 的私有成员部分:
VideoProcessor *processor;
在 mainwindow.cpp 的构造函数中添加:
processor = new VideoProcessor();
processor->moveToThread(new QThread(this));
connect(processor->thread(),
SIGNAL(started()),
processor,
SLOT(startVideo()));
connect(processor->thread(),
SIGNAL(finished()),
processor,
SLOT(deleteLater()));
connect(processor,
SIGNAL(inDisplay(QPixmap)),
ui->inVideo,
SLOT(setPixmap(QPixmap)));
connect(processor,
SIGNAL(outDisplay(QPixmap)),
ui->outVideo,
SLOT(setPixmap(QPixmap)));
processor->thread()->start();
代码解析: 首先创建了 VideoProcessor 的实例。注意不应该直接调用 VideoProcessor 的 startVideo 函数,而应该通过将一个适当的信号连接到它进行调用,在这里,使用了它自己的线程的启动信号。
在 MainWindow 析构函数中添加以下代码用于正确终止该线程:
processor->stopVideo();
processor->thread()->quit();
processor->thread()->wait();