淺析OpenCV::Mat 型別的畫素儲存機理
阿新 • • 發佈:2019-02-05
由於工作需要,經常要把一幅灰度圖儲存到一段記憶體裡,每一個位元組代表一個畫素的亮度。然後還要把這段畫素儲存到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;
}