多线程Qt + OpenCV

时间:2016-12-08 00:09:34

标签: c++ multithreading qt opencv

我打算使用opencv和Mat类型创建一个从网络摄像头摄像头接收图像的线程。然后我将它转换为QImage并使用信号将其发送到主线程。当我想在ui中的QLabel对象中将其可视化时(在转换为pixmap之后),我收到此错误:

该程序意外结束。

这是我的相机类: camera.h:

#ifndef CAMERA_H
#define CAMERA_H

#include <QObject>
#include <QThread>
#include <QtCore>
#include <QtGui>

#include <opencv2/opencv.hpp>

using namespace cv;

class Camera: public QThread
{
    Q_OBJECT
public:
    Camera();

    void run();
    bool Stop = false;

signals:
    void ImgSignal(QImage*);

private:

public slots:


};

#endif // THREAD_H

camera.cpp:

#include "camera.h"
#include <iostream>

using namespace std;

Camera::Camera()
{

}

void Camera::run()
{
    VideoCapture cap;
    cap.open(0);

    while(1){

        Mat img;
        cap >> img;

        cvtColor(img,img,CV_BGR2RGB);

        QImage image = QImage((const uchar*)img.data,img.cols,img.rows,img.step,QImage::Format_RGB888);
        emit ImgSignal(&image);
        QThread::msleep(30);
    }
}

最后我的onImgSignal函数接收图像并将其传递给gui:

void MainWindow::onImgSignal(QImage *img)
{
    QPixmap *p;
    p->fromImage(*img);

    ui->label->setPixmap(*p);

}
如果你帮助我,我会很高兴的。谢谢!

修改 当我将pixmap poiner更改为pixmap变量时,错误没有出现,但pixmap变量为null。即使我单独加载图像,它也将为null:

QPixmap p;
p.load("mark.png");
cout << p.isNull();

ui->label->setPixmap(p);

1 个答案:

答案 0 :(得分:0)

我的第一个预感是,某些对象/内存的指针被两个不同的线程意外地同时访问,从而产生访问冲突。因此,只需对传递的图像进行复制就可以解决问题(因此两个线程都不会同时访问同一图像的像素数据)。以下是您可以采取的其他一些措施:

首先,Qt中的线程实现有点不同寻常。例如,扩展QThread类不是最佳做法,因为QThread实例将 NOT 生活在新的OS级别线程中。是!这是真的。这导致许多混乱的来源,反过来导致错误。要阅读有关如何在Qt中正确执行线程的官方非官方指南,请查看this excellent article。简短摘要:QThread类将作为生成在您实例化的执行线程中的“管理”类,因此首先要了解这一点,并按预期使用QThread类。

第二次,Qt应该在信号时间猜测源和目的地是否在同一个线程中,但是我发现它有时为了安心而付出的代价是具体关于如何传递信号。这就是为什么我的代码充满了这个:

if(!connect(this,SIGNAL(colorChanged(QColor)),&ob,SLOT(onColorChanged(QColor)),(Qt::ConnectionType) (Qt::QueuedConnection | Qt::UniqueConnection) )) {
    qWarning()<<"ERROR: Could not connect "<<ob.objectName();
}

注意connect调用的最后一个参数,因为它指定了Qt::QueuedConnectionQt::UniqueConnection个连接。 Qt::QueuedConnection表示它是“线程安全的”,因为它将信号存储在线程安全的FIFO中。 Qt::UniqueConnection只是意味着连接两次会在第二次产生错误而不是创建两个连接(这可能会导致难以跟踪的错误)。

第三次,你是否在不使用Qt的情况下启动任何线程?在这种情况下,应该注意信号,因为除非您使用Qt启动的线程,否则它们可能无法正常工作。我认为上面的Qt::QueuedConnection技巧应该足够了,但我不知道。 Here更多。哦,如果OpenCV决定明知或不知不觉地启动它自己的一些线程,它们将被视为“在Qt之外开始的线程”

第四,你在调试器中运行了吗?它在什么时候崩溃?这应该是你的第一步,顺便说一句。

第五,如果所有其他方法都无法将您的代码包装在QMutex中并使用QMutexLocker以确保没有问题。或者你可以想象并使用一些线程安全的容器或其他一些。

PS:请告诉我你的票价!