0

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!

ichos
  • 1
  • 2
  • 1
    You may wanna use an open source implementation regarding the qimage-cv::mat conversion issue: https://github.com/dbzhang800/QtOpenCV/blob/master/cvmatandqimage.cpp. Good luck. – baci Oct 03 '13 at 13:56

1 Answers1

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
Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313
  • Thanks for this info! I had a success to load the image using the constructor of 'QImage' similar to what you suggested: but I wanted to use the 'loadFromData()' method. – ichos Oct 03 '13 at 20:32
  • You can't use `loadFromData()` since it doesn't do what you want to do. What you want, if you indeed care to make `QImage` a copy of the `Mat`, is pretty much a `memcpy` into the `bits()`. – Kuba hasn't forgotten Monica Oct 03 '13 at 20:35
  • Little Typo in the map: CV8_UC4 should be CV_8UC4. Trivia-Question: What would the inverted Map look like, how to see the difference in 0x**rrggbb and 0xrrggbb**. – Patrick Z Feb 09 '21 at 15:42