把QImage转换为cv::Mat

10 篇文章 0 订阅
3 篇文章 0 订阅

本文受了http://blog.csdn.net/dancing_night/article/details/51545524的启发。

QImage里面有一个指针bits(),用来指向存储像素的内存首地址。而cv::Mat也有一个成员data,同样指向存储像素的内存首地址。那么,假如我想把QImage转化为cv::Mat,是否只要调用memcpy就可以了吗?

不是的。QImage的像素存储方式与Mat既有相似之处,也有不同之处。相同之处是,像素的保存方式都是用一位数组,一行一行的储存(行主序)。不同之处是,QImage储存的每一行像素,其字节数目必须是4的整数倍。来看下面的例子,假如一个 Grayscale8格式(每一个像素用一个字节表示)的QImage由2行7列组成,各个像素的取值从1到14递增.由于QImage的每一行必须用4n个字节表示,所以每一行必须空一个字节(红色圈出的位置),保证每一行是8个字节:


为了让程序员清楚知道每一行有多少有效字节,qimage给出了bytesPerLine() 函数。在本例子中,bytesPerLine() 返回7.

而cv::Mat则不同,它存储的字节是连续的,中间不空。因此,直接用memcpy来传递数据是有问题的,会造成字节错位。

下面给出一个函数,完成从QImage向cv::Mat的转化,在转化过程中,不会造成字节错位。

头文件:

#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文件:

#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;
}

在转化过程中,cv::Mat的构造函数被告知QImage的每一行的有效数据占bytesPerLine()个字节,所以openCV库内部会做出相应的安排,避免错位。
下面的代码调用QImageToMat函数。我特意把QImage的行数设为250,不能被4整除。通过是否预定义宏 GRAY来决定QImage是灰度图还是彩图。亲测发现,不管是灰度图还是彩图,QImage向Mat的转化都是成功的。

#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;
}




  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值