简体   繁体   English

用循环停止QThread的正确方法(从opencv读取视频)

[英]The proper way to stop a QThread with a loop (that read a video from opencv)

I'd like to add some multithreading to my application (opencv-opengl integration), and I'm starting from the structure found in this answer . 我想在我的应用程序中添加一些多线程(opencv-opengl集成),并且从此答案中找到的结构开始。 For now there is a thread that grab the video frame and send it to the MainWindow, nothing more. 现在,有一个线程可以抓取视频帧并将其发送到MainWindow,仅此而已。

I have tried to search a little bit but nothing makes it clear but only make things more obscure. 我已经尝试了一些搜索,但是没有什么可以弄清楚的,只是让事情变得更加晦涩难懂。

Even if I read an article that says not to subclass QThread but use moveToThread() I read another article somewhere (other then one of the official example ) that say to do it. 即使我读了一篇文章说不是moveToThread() QThread而是使用moveToThread()我还是在某处(除了官方示例之一 moveToThread()读了另一篇文章。

If I run the application and then close it crashes. 如果我运行该应用程序,然后关闭它,则会崩溃。 If I run the application and I call the endCapture and then start again.. it crashes again. 如果我运行该应用程序,然后调用endCapture ,然后再次启动..它将再次崩溃。

Every kind of help or comment is appreciated! 各种帮助或评论都值得赞赏!

Here is the VideoThread.h: 这是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: 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();
}

And here the main: 这是主要的:

#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();
    }
}

Do not subclass QThread . 不要子类QThread Create a subclass of QObject that contain a slot. 创建包含插槽的QObject的子类。 This slot should contain the code for one iteration of your infinite loop (the loop should be removed). 此插槽应包含无限循环的一次迭代的代码(应删除循环)。 Create a QThread object and move your object to this thread using moveToThread . 创建一个QThread对象,然后使用moveToThread将对象移动到该线程。 Create a QTimer , connect it to your object's slot and start it with the desired interval (20 msec). 创建一个QTimer ,将其连接到对象的插槽,并以所需的间隔(20毫秒)启动它。 Since the object belongs to other thread, its slot will be executed periodically in that thread. 由于对象属于其他线程,因此其插槽将在该线程中定期执行。 When you want to stop the executing, call quit() and wait() on the thread. 当您想要停止执行时,请在线程上调用quit()wait() It will stop executing. 它将停止执行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM