How to convert an OpenCV cv::Mat to QImage

I am wondering how would I convert the OpenCV C++ standard cv::Mat type to QImage. I have been searching around, but have no luck. I have found some code that converts the IPlimage to QImage, but that is not what I want. Thanks.


Solution 1:

Michal Kottman's answer is valid and give expected result for some images but it'll fail on some cases. Here is a solution i found to that problem.

QImage imgIn= QImage((uchar*) img.data, img.cols, img.rows, img.step, QImage::Format_RGB888);

Difference is adding img.step part. qt won't complain without it but some images won't show properly without it. Hope this will help.

Solution 2:

Here is code for 24bit RGB and grayscale floating point. Easily adjustable for other types. It is as efficient as it gets.

QImage Mat2QImage(const cv::Mat3b &src) {
        QImage dest(src.cols, src.rows, QImage::Format_ARGB32);
        for (int y = 0; y < src.rows; ++y) {
                const cv::Vec3b *srcrow = src[y];
                QRgb *destrow = (QRgb*)dest.scanLine(y);
                for (int x = 0; x < src.cols; ++x) {
                        destrow[x] = qRgba(srcrow[x][2], srcrow[x][1], srcrow[x][0], 255);
                }
        }
        return dest;
}


QImage Mat2QImage(const cv::Mat_<double> &src)
{
        double scale = 255.0;
        QImage dest(src.cols, src.rows, QImage::Format_ARGB32);
        for (int y = 0; y < src.rows; ++y) {
                const double *srcrow = src[y];
                QRgb *destrow = (QRgb*)dest.scanLine(y);
                for (int x = 0; x < src.cols; ++x) {
                        unsigned int color = srcrow[x] * scale;
                        destrow[x] = qRgba(color, color, color, 255);
                }
        }
        return dest;
}

Solution 3:

To convert from cv::Mat to QImage, you could try to use the QImage(uchar * data, int width, int height, Format format) constructor as follows (mat is a cv::Mat) :

QImage img((uchar*)mat.data, mat.cols, mat.rows, QImage::Format_RGB32);

It is more efficient than manually converting the pixels to the QImage, but you have to keep the original cv::Mat image in memory. It can be easily converted to a QPixmap and displayed using a QLabel:

QPixmap pixmap = QPixmap::fromImage(img);
myLabel.setPixmap(pixmap);

Update

Because OpenCV uses BGR order by default, you should first use cvtColor(src, dst, CV_BGR2RGB) to get an image layout that Qt understands.

Update 2:

If the image you are trying to show has nonstandard stride (when it is non-continuous, submatrix), the image may appeard distorted. In this case, it is better to explicitly specify the stride using cv::Mat::step1():

QImage img((uchar*)mat.data, mat.cols, mat.rows, mat.step1(), QImage::Format_RGB32);