Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/124.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ Qt-在工作线程崩溃时将cv::Mat转换为QImage 介绍_C++_Multithreading_Qt_Qimage_Opencv Mat - Fatal编程技术网

C++ Qt-在工作线程崩溃时将cv::Mat转换为QImage 介绍

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

我想要的非常简单:我想要通过主ui线程中的一个按钮开始读取二进制文件的过程,让一个单独的线程处理这个过程,包括转换为
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();
    }