使用 OpenCV 的 imread() 从 qrc 读取图像
Read an image from a qrc using imread() of OpenCV
我想以这种方式使用 OpenCV 的 imread()
从 qrc 读取图像:
Mat img = imread(":/TempIcons/logo.png");
但最终 img
大小为 [0x0]。我也试过:
Mat img = imread("qrc://TempIcons/logo.png");
但我得到的尺寸是一样的。我不想在 QImage
中加载图像然后在 cv::Mat
中转换它。有没有办法以简单的方式做到这一点?如果是,我该怎么办?
谢谢
这里的问题是 imread()
从文件加载图像。
相比之下,Qt 的资源系统从图像编译数据directly into the program's executable。 Qt 的 QFile
操作知道,当为它们提供以“:/”开头的路径时,它指的是嵌入式资源,而不是磁盘上的资源。
因此,我认为您将无法使用 imread()
直接访问已放在 Qt 资源中的文件。
正如@TheDarkKnight 所指出的,imread
不了解 Qt 资源。但是,您可以编写自己的 loader,它使用 QFile
从资源中检索二进制数据,并使用 imdecode
(由 [=15= 内部完成) ]) 读取图像:
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
加载图像,然后使用 this 代码加载 QImage
并转换为 Mat
,包括克隆和不克隆。 loadFromQrc
结果比加载 QImage
并将其转换为 Mat
.
快 10 倍
结果以毫秒为单位:
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;
}
我想以这种方式使用 OpenCV 的 imread()
从 qrc 读取图像:
Mat img = imread(":/TempIcons/logo.png");
但最终 img
大小为 [0x0]。我也试过:
Mat img = imread("qrc://TempIcons/logo.png");
但我得到的尺寸是一样的。我不想在 QImage
中加载图像然后在 cv::Mat
中转换它。有没有办法以简单的方式做到这一点?如果是,我该怎么办?
谢谢
这里的问题是 imread()
从文件加载图像。
相比之下,Qt 的资源系统从图像编译数据directly into the program's executable。 Qt 的 QFile
操作知道,当为它们提供以“:/”开头的路径时,它指的是嵌入式资源,而不是磁盘上的资源。
因此,我认为您将无法使用 imread()
直接访问已放在 Qt 资源中的文件。
正如@TheDarkKnight 所指出的,imread
不了解 Qt 资源。但是,您可以编写自己的 loader,它使用 QFile
从资源中检索二进制数据,并使用 imdecode
(由 [=15= 内部完成) ]) 读取图像:
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
加载图像,然后使用 this 代码加载 QImage
并转换为 Mat
,包括克隆和不克隆。 loadFromQrc
结果比加载 QImage
并将其转换为 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;
}