ichos
ichos

Reputation: 1

Convert cv::mat to QImage using QImage::loadFromData

I’ve found similar topics but not this particular one. Any ideas what’s wrong with the following code? It returns ‘loaded=false’, which obviously means that image data cannot be loaded.

cv::Mat mymat;
QImage qimg;
mymat = cv::imread("C:\\testimages\\img1.png");
int len = mymat.total()*mymat.elemSize();
bool loaded = qimg.loadFromData((uchar*)mymat.data, len, "PNG");

Thank you!

Upvotes: 0

Views: 1214

Answers (1)

The cv::Mat type holds a decoded image. Thus you cannot ask QImage to decode it again using the loadFromData() method.

You need to set up an image with format matching the element type, retrieved using Mat::type(), then either copy the raw data from the matrix to the image, or set up a QImage header for the data. In OpenCV terminology, a "header" means an object that doesn't hold its own data.

The code below sets up a header QImage.

QMap<int, QImage::Format> fmtMap;
fmtMap.insert(CV8_UC4, QImage::Format_ARGB32);
fmtMap.insert(CV_8UC3, QImage::Format_RGB888)
// We should convert to a color image since 8-bit indexed images can't be painted on
cv::Mat mat = cv::imread("C:\\testimages\\img1.png", CV_LOAD_IMAGE_COLOR);
Q_ASSERT(fmtMap.contains(cvImage.type());
Q_ASSERT(mat.isContinuous());
QImage img(cvImage.data, cvImage.cols, cvImage.rows, fmtMap[cvImage.type()]);
// The matrix *must* outlive the image, otherwise the image will access a dangling pointer to data

It may be easier to load the image using QImage, and then create a header matrix for it.

QMap<QImage::Format, int> fmtMap;
fmtMap.insert(QImage::Format_ARGB32, CV8_UC4);
fmtMap.insert(QImage::Format_RGB32, CV8_UC4);
fmtMap.insert(QImage::Format_RGB888, CV_8UC3);
QImage img;
img.load("C:\\testimages\\img1.png");
Q_ASSERT(fmtMap.contains(img.format()));
cv::Mat mat(img.height(), img.width(), fmtMap[img.format()], img.bits());
// The image *must* outlive the matrix, otherwise the matrix will access a dangling pointer to data

Upvotes: 1

Related Questions