我想爲我的應用程序(opencv-opengl集成)添加一些多線程,並且我從this answer中找到的結構開始。現在有一個線程抓取視頻幀並將其發送到MainWindow,僅此而已。用循環停止QThread的正確方法(從opencv讀取視頻)
我試圖搜索一點點,但沒有明確說明,但只是使事情更加晦澀。
即使我讀an article,說沒有繼承QThread
但使用moveToThread()
我讀到另一篇文章的地方(其他然後one of the official example),該說的去做。
如果我運行該應用程序,然後關閉它崩潰。 如果我運行的應用程序,我打電話endCapture
,然後再次開始..它再次崩潰。
各種幫助或評論感謝!
這裏是VideoThread.h:
#ifndef VIDEOTHREAD_H
#define VIDEOTHREAD_H
#include <QMutex>
#include <QImage>
#include <QThread>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
class VideoThread : public QThread
{
Q_OBJECT
public:
explicit VideoThread(QObject *parent = 0);
~VideoThread();
protected:
void run();
private:
cv::VideoCapture video;
QMutex m_AbortCaptureLock;
bool m_AbortCapture;
signals:
void sendImage(QImage);
public slots:
void endCapture();
};
#endif // VIDEOTHREAD_H
VideoThread.cpp:
#include "videothread.h"
#include <QDebug>
VideoThread::VideoThread(QObject *parent) :
QThread(parent)
{
qDebug() << "VideoThread > ctor.";
}
VideoThread::~VideoThread()
{
qDebug() << "VideoThread > dtor";
if(video.isOpened()) {
video.release();
qDebug() << "Camera successfully disconnected.";
}
}
void VideoThread::run()
{
m_AbortCapture = false;
video = cv::VideoCapture(0);
qDebug() << "VideoThread::run..";
while(true)
{
m_AbortCaptureLock.lock();
if (m_AbortCapture) {
qDebug() << "VideoThread::run > abort capture..";
break;
}
m_AbortCaptureLock.unlock();
cv::Mat cvFrame;
video >> cvFrame;
if(cvFrame.empty()) continue;
// convert the Mat to a QImage
QImage qtFrame(cvFrame.data, cvFrame.size().width, cvFrame.size().height, cvFrame.step, QImage::Format_RGB888);
qtFrame = qtFrame.rgbSwapped();
// queue the image to the gui
emit sendImage(qtFrame);
msleep(20);
}
}
void VideoThread::endCapture()
{
qDebug() << "VideoThread::endCapture()";
m_AbortCaptureLock.lock();
m_AbortCapture = true;
m_AbortCaptureLock.unlock();
}
這裏主要:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "opencv_glwidget.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
OpenCV_GLWidget *w = new OpenCV_GLWidget();
w->setParent(this->centralWidget());
connect(ui->checkBox, SIGNAL(toggled(bool)),
this, SLOT(toggle(bool)));
ui->checkBox->toggle();
connect(&thread, SIGNAL(sendImage(QImage)),
w, SLOT(renderImage(QImage)));
thread.start();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::toggle(bool n)
{
if(n) {
thread.start();
} else {
thread.endCapture();
}
}
no'run()'?沒有'bAbort'標誌?只需啓動/停止定時器即可處理線程的啓動和停止。似乎大大簡化了事情。但是說,我想暫停視頻:停止定時器並等待...並重新啓動?只需重新啓動計時器?不需要喚醒線程? – nkint
請注意,您需要將'video'設爲類成員變量。它將在插槽調用之間保留。如果您想重新啓動視頻,您應該創建另一個插槽來重置「video」值。另外,只有'stop()'可以'啓動()'計時器來暫停執行。當定時器停止時,線程繼續執行但不執行任何操作。此外,現在我認爲20毫秒定時器可能會產生很多開銷。最好將其間隔增加到100-500毫秒,並在插槽中執行多次迭代(而不是一次迭代)。 –