使用 OpenCV 的 imread() 从 qrc 读取图像

2021-12-09 00:00:00 opencv qt c++ imread

我想以这种方式使用 OpenCV 的 imread() 从 qrc 读取图像:

I want to read an image from a qrc using imread() of OpenCV in this way:

Mat img = imread(":/TempIcons/logo.png");

但最终的 img 大小是 [0x0].我也试过:

but the final img size is [0x0]. I have also tried:

Mat img = imread("qrc://TempIcons/logo.png");

但我得到的大小是一样的.我不想在 QImage 中加载图像,然后在 cv::Mat 中转换它.有没有办法以简单的方式做到这一点?如果是,我该怎么做?.

but the size I get is the same. I don't want to load the image in a QImage to then transform it in a cv::Mat. Is there a way to do this in a easy way?. If it is, how can I do it?.

谢谢

推荐答案

正如@TheDarkKnight 所指出的,imread 不知道 Qt 资源.但是,您可以编写自己的 loader,它使用 QFile 从资源中检索二进制数据,并使用 imdecode(由 imdecode 在内部完成)code>imread) 读取图像:

As @TheDarkKnight pointed out, imread is not aware of Qt resources. You can however write your own loader, that uses QFile to retrieve the binary data from the resource, and uses imdecode (as done internally by imread) to read the image:

Mat loadFromQrc(QString qrc, int flag = IMREAD_COLOR)
{
    //double tic = double(getTickCount());

    QFile file(qrc);
    Mat m;
    if(file.open(QIODevice::ReadOnly))
    {
        qint64 sz = file.size();
        std::vector<uchar> buf(sz);
        file.read((char*)buf.data(), sz);
        m = imdecode(buf, flag);
    }

    //double toc = (double(getTickCount()) - tic) * 1000.0 / getTickFrequency();
    //qDebug() << "OpenCV loading time: " << toc;

    return m;
}

你可以这样称呼它:

Mat m = loadFromQrc("qrc_path");

或指定一个标志:

Mat m = loadFromQrc("qrc_path", IMREAD_GRAYSCALE);

<小时>

性能

我尝试使用 loadFromQrc 加载图像,并使用 QImage 并转换为 Matasmaloney.com/2013/11/code/converting-between-cvmat-and-qimage-or-qpixmap/" rel="noreferrer">this 代码,包括克隆和不克隆.loadFromQrc 结果比加载 QImage 并将其转换为 Mat 快 10 倍.

I tried loading the image with loadFromQrc, and loading the QImage and converting to Mat using this code, both with and without cloning. loadFromQrc results to be 10 time faster then loading a QImage and convert it to Mat.

结果以毫秒为单位:

Load Mat                :  4.85965
QImage to Mat (no clone):  49.3999
QImage to Mat (clone)   :  49.8497

测试代码:

#include <vector>
#include <iostream>
#include <QDebug>
#include <QtWidgets>

#include <opencv2/opencv.hpp>
using namespace cv;

Mat loadFromQrc(QString qrc, int flag = IMREAD_COLOR)
{
    QFile file(qrc);
    Mat m;
    if(file.open(QIODevice::ReadOnly))
    {
        qint64 sz = file.size();

        std::vector<uchar> buf(sz);
        file.read((char*)buf.data(), sz);
        m = imdecode(buf, flag);
    }
    return m;
}

cv::Mat QImageToCvMat( const QImage &inImage, bool inCloneImageData = true )
{
    switch ( inImage.format() )
    {
    // 8-bit, 4 channel
    case QImage::Format_RGB32:
    {
        cv::Mat  mat( inImage.height(), inImage.width(), CV_8UC4, const_cast<uchar*>(inImage.bits()), inImage.bytesPerLine() );

        return (inCloneImageData ? mat.clone() : mat);
    }

        // 8-bit, 3 channel
    case QImage::Format_RGB888:
    {
        if ( !inCloneImageData )
            qWarning() << "ASM::QImageToCvMat() - Conversion requires cloning since we use a temporary QImage";

        QImage   swapped = inImage.rgbSwapped();

        return cv::Mat( swapped.height(), swapped.width(), CV_8UC3, const_cast<uchar*>(swapped.bits()), swapped.bytesPerLine() ).clone();
    }

        // 8-bit, 1 channel
    case QImage::Format_Indexed8:
    {
        cv::Mat  mat( inImage.height(), inImage.width(), CV_8UC1, const_cast<uchar*>(inImage.bits()), inImage.bytesPerLine() );

        return (inCloneImageData ? mat.clone() : mat);
    }

    default:
        qWarning() << "ASM::QImageToCvMat() - QImage format not handled in switch:" << inImage.format();
        break;
    }

    return cv::Mat();
}

int main(int argc, char *argv[])
{
    QString url = "...";

    {
        double tic = double(getTickCount());

        Mat m1 = loadFromQrc(url);

        double toc = (double(getTickCount()) - tic) * 1000.0 / getTickFrequency();
        qDebug() << "Load Mat: " << toc;

        if(m1.data != NULL)
        {
            imshow("m1", m1);
            waitKey(1);
        }
    }


//    {
//        double tic = double(getTickCount());

//        QImage img;
//        img.load(url);
//        Mat m2 = QImageToCvMat(img, false);

//        double toc = (double(getTickCount()) - tic) * 1000.0 / getTickFrequency();
//        qDebug() << "QImage to Mat (no clone): " << toc;

//        if(m2.data != NULL)
//        {
//            imshow("m2", m2);
//            waitKey(1);
//        }
//    }


//    {
//        double tic = double(getTickCount());

//        QImage img;
//        img.load(url);
//        Mat m3 = QImageToCvMat(img, true);

//        double toc = (double(getTickCount()) - tic) * 1000.0 / getTickFrequency();
//        qDebug() << "QImage to Mat (clone): " << toc;

//        if(m3.data != NULL)
//        {
//            imshow("m3", m3);
//            waitKey(1);
//        }
//    }

    waitKey();
    return 0;
}

相关文章