我打算使用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);
答案 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::QueuedConnection
和Qt::UniqueConnection
个连接。 Qt::QueuedConnection
表示它是“线程安全的”,因为它将信号存储在线程安全的FIFO中。 Qt::UniqueConnection
只是意味着连接两次会在第二次产生错误而不是创建两个连接(这可能会导致难以跟踪的错误)。
第三次,你是否在不使用Qt的情况下启动任何线程?在这种情况下,应该注意信号,因为除非您使用Qt启动的线程,否则它们可能无法正常工作。我认为上面的Qt::QueuedConnection
技巧应该足够了,但我不知道。 Here更多。哦,如果OpenCV决定明知或不知不觉地启动它自己的一些线程,它们将被视为“在Qt之外开始的线程”。
第四,你在调试器中运行了吗?它在什么时候崩溃?这应该是你的第一步,顺便说一句。
第五,如果所有其他方法都无法将您的代码包装在QMutex
中并使用QMutexLocker
以确保没有问题。或者你可以想象并使用一些线程安全的容器或其他一些。
PS:请告诉我你的票价!