浅析OpenCV::Mat 类型的像素保存机理

由于工作需要,经常要把一幅灰度图保存到一段内存里,每一个字节代表一个像素的亮度。然后还要把这段像素保存到opencv的Mat变量里面。下面用程序来测试,Mat里面的像素数据是否也指向同一段内存。

#include "matprobe.h"
#include <opencv2/opencv.hpp>  
#include <QImage>
#include <QPainter>
#include <QDebug>

using namespace cv; 

#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")


unsigned char * m_pData = new unsigned char[256 * 256];
QImage m_Img;

MatProbe::MatProbe(QWidget *parent)
	: QMainWindow(parent)
{
	ui.setupUi(this);
	for(int k = 0; k<256;k++)
	{
		for(int l = 0; l<256; l++)
		{
			m_pData[l * 256 + k] = k;
		}
	}
}

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

void MatProbe::paintEvent(QPaintEvent *e)
{
	QImage img(m_pData, 256, 256, 256, QImage::Format_Grayscale8);
	QImage m_Img(256, 256,  QImage::Format_Grayscale8);
	QPainter qp;
	qp.begin(&m_Img);
	qp.fillRect(m_Img.rect(), QBrush(img));
	qp.end();

//	QPainter qp;
	qp.begin(this);
	qp.drawImage(rect(), m_Img, m_Img.rect());
	qp.end();
}

void MatProbe::mouseDoubleClickEvent(QMouseEvent *e)
{
	Mat mtx(256, 256, CV_8UC1, m_pData);
	delete [] m_pData;
	m_pData = NULL;
	bool b = imwrite("D:\\mtx.jpg", mtx);
	qDebug()<<b;
}
运行后的对话框是一个从黒向白的渐变:

然后双击对话框,并通过断点来观察Mat的像素保存地址:


注意两个红圈标注的地址,一个是原始数据的地址,一个是Mat的像素的地址,两者相同。这说明程序只是把m_pData的地址传到mtx,并没有给mtx开辟新内存(所谓的“浅拷贝”)。mouseDoubleClickEvent函数执行完毕后,保存下来的图像《mtx.jpg》也不是一幅渐变的图,而是混乱的灰度图。尽管我没有对Mat的像素做任何直接的操作,但是我释放了m_pData,导致mtx的内容发生变化:


假如程序员需要建立一个和m_pData不相关的Mat变量,可以利用已有的mtx,做一次 clone()操作,获取新的Mat类型的变量。clone是“深拷贝”,它的返回值是一个Mat类型,且这个返回变量拥有自己的内存,而不是跟前面的Mat变量共享同一段内存。

对代码做如下修改,保存的图像就不会出问题:

void MatProbe::mouseDoubleClickEvent(QMouseEvent *e)
{
	Mat mtx(256, 256, CV_8UC1, m_pData);
	/************注意下面语句*******************/
	Mat mtx_clone = mtx.clone();

	delete [] m_pData;
	m_pData = NULL;
//还有下面:
	bool b = imwrite("D:\\mtx.jpg", mtx_clone);
	qDebug()<<b;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值