QImage and OpenCV Mat problem
-
Hi all.
I'm using Windows 10 and Linux 18.04 with Qt 5.12 and OpenCV 4.0.1.
I have a problem when loading a QImage and then converting it to an OpenCV Mat.
It seems that QImage has more data in its array than the Mat.Properties:
Qimage: width=1001px, height=1001px, type=QImage::Format_Grayscale, bytesPerLine=1004
Mat: width=1001px, height=1001px, type=CV_8UC1, bytesPerLine=1001This problem does only occur when the image width is odd.
Does anyone know why and how to solve it?
The result images are confusing. The pixels are shifted.
Regards,
Oliver -
Hi,
IIRC, it will depend on the image format and size. There can be padding involved.
In any case, it's usually done the other way around: load image with OpenCV, apply processing and move then to QImage.
What are you currently doing ?
-
Hi,
currently I am loading a QImage from a file.
Then I encode it to Base64-Format and insert the Base64-String into an xml-structure.This xml is sended through tcp/ip to a server where the server is decoding the Base64-String back to an image. And then I am processing the image with OpenCV.
My current workaround is to save the QImage to hard disk and load again it with OpenCV. That works.
Regards,
Oliver -
That might be a silly question but why not directly encode the file content ?
-
There's no problem with that but you didn't gave much information about your application so it's not easy to provide recommendations.
-
@SGaist
I figured out that the main problem is not transferring the image but loading the image with QImage. Even when I just load the image from harddisk the bytesPerLine is 1004 for an 8 bit pixel image with 1001px width. So as already mentioned from @beecksche the 32-bit alignment will prevent the correct direct conversion from QImage to cv::Mat. -
Afaics OpenCV::Mat also supports padding. Images are always padded so it would be better to teach OpenCV::Mat about it.
-
QImage Mat2QImage(cv::Mat const& src)
{
cv::Mat temp; // make the same cv::Mat
cvtColor(source, temp,CV_BGR2RGB); // cvtColor Makes a copt, that what i need
QImage dest((const uchar *) temp.data, temp.cols, temp.rows, temp.step, QImage::Format_RGB888);
dest.bits(); // enforce deep copy, see documentation
// of QImage::QImage ( const uchar * data, int width, int height, Format format )
return dest;
}
// work with QT5.15.0 and OpenCv 4.7.0 -
The decision to always have 4byte aligned scanlines is definitely one of the weirdest things about interoperating QImage with other API's. Most in-memory image formats for other API's are densely packed (at least by default). And it's something you only really notice with odd widths. (And RGBA format is 4 bytes per pixel so it's scanlines are always 4 byte aligned without padding, even for odd-width images.)
If you don't know the quirk, it's annoyingly easy to have a large test suite of different image sizes and formats, and still completely miss the combination of odd width and odd bytes per pixel.
-
Christian Ehrlicher Lifetime Qt Championreplied to wrosecrans on last edited by Christian Ehrlicher
@wrosecrans said in QImage and OpenCV Mat problem:
Most in-memory image formats for other API's are densely packed (at least by default).
Then you should never decode a video stream with ffmpeg...
Images in video streams are normally 32 byte aligned nowadays to perfectly match to cpu vector instructions and caches.
The only thing I miss in QImage is to be able to specify this alignment in the ctor like e.g. av_image_alloc() allows.