C++ Qt-在工作线程崩溃时将cv::Mat转换为QImage 介绍
我想要的非常简单:我想要通过主ui线程中的一个按钮开始读取二进制文件的过程,让一个单独的线程处理这个过程,包括转换为C++ Qt-在工作线程崩溃时将cv::Mat转换为QImage 介绍,c++,multithreading,qt,qimage,opencv-mat,C++,Multithreading,Qt,Qimage,Opencv Mat,我想要的非常简单:我想要通过主ui线程中的一个按钮开始读取二进制文件的过程,让一个单独的线程处理这个过程,包括转换为QImage,并将这个图像返回到主ui线程,它应该显示在标签中 因此,我使用Qt的信号/插槽机制及其线程功能 我allready有一个单线程工作解决方案,但是当使用线程尝试时,它会在完全任意的步骤上崩溃,我不理解,因为整个过程是完全封装的,而不是时间关键的 工作单线程解决方案: TragVisMain是一个qmain窗口: class TragVisMain : public Q
QImage
,并将这个图像返回到主ui线程,它应该显示在标签中
因此,我使用Qt的信号/插槽机制及其线程功能
我allready有一个单线程工作解决方案,但是当使用线程尝试时,它会在完全任意的步骤上崩溃,我不理解,因为整个过程是完全封装的,而不是时间关键的
工作单线程解决方案:
TragVisMain
是一个qmain窗口
:
class TragVisMain : public QMainWindow
按下按钮readBinSingle
开始该过程:
void TragVisMain::on_readBinSingle_clicked()
{
// Open binary file
FILE *imageBinFile = nullptr;
imageBinFile = fopen("imageFile.bin", "rb");
if(imageBinFile == NULL) {
return;
}
// Get binary file size
fseek(imageBinFile, 0, SEEK_END); // seek to end of file
size_t size = static_cast<size_t>(ftell(imageBinFile)); // get current file pointer
fseek(imageBinFile, 0, SEEK_SET);
// Read binary file
void *imageData = malloc(size);
fread(imageData, 1, size, imageBinFile);
// Create cv::Mat
cv::Mat openCvImage(1024, 1280, CV_16UC1, imageData);
openCvImage.convertTo(openCvImage, CV_8UC1, 0.04); // Convert to 8 Bit greyscale
// Transform to QImage
QImage qImage(
openCvImage.data,
1280,
1024,
QImage::Format_Grayscale8
);
// Show image in label, 'imageLabel' is class member
imageLabel.setPixmap(QPixmap::fromImage(qImage));
imageLabel.show();
}
docamerastaff
只是一个QObject
:
class DoCameraStuff : public QObject
{
Q_OBJECT
public:
explicit DoCameraStuff(QObject *parent = nullptr);
public slots:
void readBinaryAndShowBinPic();
signals:
void showQImage(const QImage &image);
};
将dcs
移动到workerThread
和connect
在TragVisMain
的构造函数中执行以下操作:
TragVisMain::TragVisMain(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::TragVisMain),
dcs()
{
ui->setupUi(this);
dcs.moveToThread(&workerThread);
// Object should be deletable after the thread finished!
connect(&workerThread, &QThread::finished, &dcs, &QObject::deleteLater);
// For starting the image processing
connect(this, &TragVisMain::loadBinaryImage, &dcs, &DoCameraStuff::readBinaryAndShowBinPic);
// Showing QImage after image processing is done
connect(&dcs, &DoCameraStuff::showQImage, this, &TragVisMain::setImage);
// Start workerThread
workerThread.start();
}
按下readBinSingle
按钮可启动图像处理:
void TragVisMain::on_readBin_clicked()
{
emit loadBinaryImage(); // slot: readBinaryAndShowBinPic
}
该过程发生在docamerastaff::readbinaryandbshowbinpic
:
void DoCameraStuff::readBinaryAndShowBinPic() {
// Exact same code from single thread solution:
// Open binary file
FILE *imageBinFile = nullptr;
imageBinFile = fopen("imageFile.bin", "rb");
if(imageBinFile == NULL) {
return;
}
// Get binary file size
fseek(imageBinFile, 0, SEEK_END); // seek to end of file
size_t size = static_cast<size_t>(ftell(imageBinFile)); // get current file pointer
fseek(imageBinFile, 0, SEEK_SET);
// Read binary file
void *imageData = malloc(size);
fread(imageData, 1, size, imageBinFile);
// Create cv::Mat
cv::Mat openCvImage(1024, 1280, CV_16UC1, imageData);
openCvImage.convertTo(openCvImage, CV_8UC1, 0.04); // Convert to 8 Bit greyscale
// Transform to QImage
QImage qImage(
openCvImage.data,
1280,
1024,
QImage::Format_Grayscale8
);
// Send qImage to 'TragVisMain'
emit showQImage(qImage);
}
问题 多线程尝试只是在不同的步骤中使整个应用程序崩溃,没有任何消息。但老实说我不知道。对我来说,
docamerastaff
类是成员函数中与时间无关的东西,没有任何关键关系
我还检查了docamerastaff::readbinary和showbinpic中使用的一些函数是否不是线程安全的,但在同等条件下,我没有发现与
、cv::Mat
和QImage
有关的任何问题
因此:
为什么多线程尝试会崩溃
为了使线程中的进程不会崩溃,需要应用哪些更改
我非常感谢您的帮助。它没有工作的机会,因为QImage
包装了瞬态数据,然后由cvMat
释放。至少应该发出图像的副本(字面意思是qImage.copy()
。理想情况下,您应该在QImage
的删除程序中包装cvMat
生命周期管理,这样就不需要复制,矩阵会随着包装它的图像一起被破坏。由于通常需要在cv::Mat
和QImage
之间进行格式转换,因此最好执行转换在源cv::Mat
和另一个包装QImage
的cv::Mat
拥有的内存之间。该解决方案避免了内存重新分配,因为QImage
可以保留在执行转换的类中。它也可以与Qt 4兼容,其中QImage
不支持删除程序
请参阅和。它没有工作的机会,因为QImage
包装瞬态数据,然后由cvMat
释放。您至少应该发出图像的副本(字面意思是QImage.copy()
。理想情况下,您应该在QImage
的删除程序中包装cvMat
生命周期管理,这样就不需要复制,矩阵会随着包装它的图像一起被破坏。由于通常需要在cv::Mat
和QImage
之间进行格式转换,因此最好执行转换在源cv::Mat
和另一个包装QImage
的cv::Mat
拥有的内存之间。该解决方案避免了内存重新分配,因为QImage
可以保留在执行转换的类中。它也可以与Qt 4兼容,其中QImage
不支持删除程序
请参阅和。不要使用void setImage(QImage*img);
,而是使用void setImage(const QImage&img);
我会更改它,问题仍然存在……我还尝试了正常参数“setImage(QImage img)”和参考“setImage(QImage&img)”“QImage&img
不同于const QImage&img
它可能不是解决方案,但您必须更正它。慢慢来,删除所有复制错误,没有人会催您发帖。另一方面,您是否使用过调试器来查看问题所在?:)不要使用void setImage(QImage*img);
,改为使用void setImage(const QImage&img);
我将更改它,问题仍然存在……我还尝试了正常参数“setImage(QImage img)”和参考“setImage(QImage&img)“QImage&img
不同于const QImage&img
它可能不是解决方案,但您必须更正它。慢慢来,删除所有复制错误,没有人会催您发帖。另一方面,您是否使用了调试器来查看问题所在?:)
void DoCameraStuff::readBinaryAndShowBinPic() {
// Exact same code from single thread solution:
// Open binary file
FILE *imageBinFile = nullptr;
imageBinFile = fopen("imageFile.bin", "rb");
if(imageBinFile == NULL) {
return;
}
// Get binary file size
fseek(imageBinFile, 0, SEEK_END); // seek to end of file
size_t size = static_cast<size_t>(ftell(imageBinFile)); // get current file pointer
fseek(imageBinFile, 0, SEEK_SET);
// Read binary file
void *imageData = malloc(size);
fread(imageData, 1, size, imageBinFile);
// Create cv::Mat
cv::Mat openCvImage(1024, 1280, CV_16UC1, imageData);
openCvImage.convertTo(openCvImage, CV_8UC1, 0.04); // Convert to 8 Bit greyscale
// Transform to QImage
QImage qImage(
openCvImage.data,
1280,
1024,
QImage::Format_Grayscale8
);
// Send qImage to 'TragVisMain'
emit showQImage(qImage);
}
void TragVisMain::setImage(const QImage &img)
{
imageLabel.setPixmap(QPixmap::fromImage(img));
imageLabel.show();
}