Monday, 19 August 2013

Convert between cv::mat and Qimage correctly

This post will talk about how to convert between cv::Mat and QImage.The solution is far from perfect and need to refine, please give me some helps if you know how to make the codes become better.
Conversion between QImage and cv::Mat have some traps to deal with, I will write the codes step by step and explain why do I develop it like that, what kind of traps I want to deal with.

The results may work or may not work because the bytes of each row(we call it stride) may vary, vary or not is depends on the image.To prevent this kind of tragedy, we need to tell the QImage how many bytes per row by mat.step.

Convert cv::Mat to QImage by copy

Warning--this is dangerous

This codes looks unharm at first, you could found this kind of suggestion from many forums, but this answer is partially work only.It create an empty mat, and copy the data of the mat to the QImage by memcpy,fast and low calorie?Wrong, because we didn't specify how many bytes per row when we construct the QImage.The correct solution should be

Convert QImage to cv::Mat by copy

I believe many c++ programmers would feel uncomfortable when you find out I used const_cast to cast the constness,believe it or not, I have the same feel as yours, but I can't find out a better way to copy the buffer.

Other traps

Do we deal with all of the hassles already?Not yet, the default channels of the openCV is BGR but the QImage is RGB, that means you need to convert the channels from RGB to BGR when convert between three channels image and vice versa.In QImage, you could call "rgbSwapped()"; In cv::Mat, you could call cv::cvtColor to convert the channels.

Final results

It is a little bit annoying to write the conversion codes everytime, so I do some simple encapsulation on it, you could download the codes from github

These functions do not handles all of the image types between QImage and cv::Mat, but it should work on most of the images.Take it if you like and do whatever you want.