由于工作需要,经常要把一幅灰度图保存到一段内存里,每一个字节代表一个像素的亮度。然后还要把这段像素保存到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;
}