Convert QImage to cv::Mat

Keywords: OpenCV

This article is inspired by http://blog.csdn.net/dancing_night/article/details/51545524.

There is a pointer bits() in QImage to point to the memory header address of the stored pixels. And cv::Mat also has a member data, which also points to the memory header address of the storage pixel. So, if I want to convert QImage into cv::Mat, can I just call memcpy?

No, it isn't. There are similarities and differences between QImage and Mat in pixel storage. In the same way, pixels are stored in a single-digit array, row by row (row main order). The difference is that for each row of pixels stored in QImage, the number of bytes must be an integral multiple of 4. Let's look at the following example. If a Grayscale 8 format QImage is composed of two rows and seven columns, the values of each pixel increase from 1 to 14. Since each row of QImage must be represented by four n bytes, each row must be empty one byte (the position circled in red) to ensure that each row is eight bytes:


To let programmers know exactly how many valid bytes are in each line, qimage gives the bytes PerLine () function. In this example, bytesPerLine() returns 7.

Unlike cv::Mat, the bytes it stores are continuous and not empty in the middle. Therefore, it is problematic to transfer data directly with memcpy, which will cause byte dislocation.

Here is a function that completes the transformation from QImage to cv::Mat without causing byte dislocation.

Head file:

#pragma once
#include <opencv2/opencv.hpp>  
#include <QImage>
#include <QPainter>
#include <QDebug>


#pragma comment(lib, "E:\\cv\\opencv\\build\\x86\\vc11\\lib\\opencv_core249d.lib")
#pragma comment(lib, "E:\\cv\\opencv\\build\\x86\\vc11\\lib\\opencv_imgproc249d.lib")
#pragma comment(lib, "E:\\cv\\opencv\\build\\x86\\vc11\\lib\\opencv_highgui249d.lib")
#pragma comment(lib, "E:\\cv\\opencv\\build\\x86\\vc11\\lib\\opencv_ml249d.lib")
#pragma comment(lib, "E:\\cv\\opencv\\build\\x86\\vc11\\lib\\opencv_video249d.lib")
#pragma comment(lib, "E:\\cv\\opencv\\build\\x86\\vc11\\lib\\opencv_features2d249d.lib")
#pragma comment(lib, "E:\\cv\\opencv\\build\\x86\\vc11\\lib\\opencv_calib3d249d.lib")
#pragma comment(lib, "E:\\cv\\opencv\\build\\x86\\vc11\\lib\\opencv_objdetect249d.lib")
#pragma comment(lib, "E:\\cv\\opencv\\build\\x86\\vc11\\lib\\opencv_contrib249d.lib")
#pragma comment(lib, "E:\\cv\\opencv\\build\\x86\\vc11\\lib\\opencv_legacy249d.lib")
#pragma comment(lib, "E:\\cv\\opencv\\build\\x86\\vc11\\lib\\opencv_flann249d.lib")

cv::Mat QImageToMat(QImage image);
cpp file:

#include "cvUtility.h"


cv::Mat QImageToMat(QImage image)
{
	cv::Mat mat;
	switch (image.format())
	{
	case QImage::Format_ARGB32:
	case QImage::Format_RGB32:
	case QImage::Format_ARGB32_Premultiplied:
		mat = cv::Mat(image.height(), image.width(), CV_8UC4, (void*)image.constBits(), image.bytesPerLine());
		break;
	case QImage::Format_RGB888:
		mat = cv::Mat(image.height(), image.width(), CV_8UC3, (void*)image.constBits(), image.bytesPerLine());
		cv::cvtColor(mat, mat, CV_BGR2RGB);
		break;
	case QImage::Format_Grayscale8:
		mat = cv::Mat(image.height(), image.width(), CV_8UC1, (void*)image.constBits(), image.bytesPerLine());
		break;
	}
	return mat;
}

In the transformation process, the constructor of cv::Mat is told that the valid data of each line of QImage takes up bytes of PerLine (), so the openCV library will make corresponding arrangements to avoid dislocation.
The following code calls the QImageToMat function. I deliberately set the number of rows in QImage to 250, which cannot be divided by 4. It determines whether QImage is a gray or a color image by predefining macro GRAY. It is found that the transformation from QImage to Mat is successful in both gray and color images.

#include "mat_qimage.h"
#include "cvUtility.h"

#define GRAY

const int iWidth = 250, iHeight = 255;
unsigned char * m_pData = new unsigned char[iWidth * iHeight];
QImage m_Img;

Mat_QImage::Mat_QImage(QWidget *parent)
	: QMainWindow(parent)
{
	ui.setupUi(this);

#if defined(GRAY)
	for(int k = 0; k<iWidth;k++)
	{
		for(int l = 0; l<iHeight; l++)
		{
			m_pData[l * iWidth + k] = k;
		}
	}

	QImage img(m_pData, iWidth, iHeight, iWidth, QImage::Format_Grayscale8);
	qDebug()<<img.bytesPerLine();
	m_Img = QImage(iWidth, iHeight, QImage::Format_Grayscale8);
#else
	QImage img;
	img.load(QString("E:\\merge.bmp"));
	m_Img = QImage(iWidth, iHeight, img.format());
#endif
	QPainter qp;
	qp.begin(&m_Img);
	qp.drawImage(m_Img.rect(), img, img.rect());
	qp.end();
}

Mat_QImage::~Mat_QImage()
{
	if(m_pData)
		delete [] m_pData;
}

void Mat_QImage::paintEvent(QPaintEvent *e)
{
	QPainter qp;
	qp.begin(this);
	qp.drawImage(rect(), m_Img, m_Img.rect());
	qp.end();
}

void Mat_QImage::mouseDoubleClickEvent(QMouseEvent *e)
{
	cv::Mat mtx = QImageToMat(m_Img);
	
	bool b = cv::imwrite("E:\\mtx.jpg", mtx);
	qDebug()<<b;
}




Posted by portrower8 on Tue, 26 Mar 2019 02:51:29 -0700