天天看點

OpenCV中矩陣類詳解之三:CvMat,Mat和IplImage之間的轉化和拷貝

在OpenCV中Mat、CvMat和IplImage類型都可以代表和顯示圖像。IplImage由CvMat派生,而CvMat由CvArr派生即CvArr -> CvMat -> IplImage,Mat類型則是C++版本的矩陣類型(CvArr用作函數的參數,無論傳入的是CvMat或IplImage,内部都是按CvMat處理)。

其中Mat類型側重于計算,數學性較高,OpenCV對Mat類型的計算也進行了優化;而CvMat和IplImage類型更側重于"圖像",OpenCV對其中的圖像操作(縮放、單通道提取、圖像門檻值操作等)進行了優化。很多時候需要三種類型的互相轉化,這裡簡要介紹一下。

========================CvMat和Mat間的轉化和拷貝========================

1、CvMat之間的複制

//注意:深拷貝 - 單獨配置設定空間,兩者互相獨立
CvMat* a;
CvMat* b = cvCloneMat(a);	//copy a to b
           

2、Mat之間的複制

//注意:淺拷貝 -  不複制資料隻建立矩陣頭,資料共享(更改a,b,c的任意一個都會對另外2個産生同樣的作用)
Mat a;
Mat b = a; //a "copy" to b
Mat c(a); //a "copy" to c

//注意:深拷貝
Mat a;
Mat b = a.clone(); //a copy to b
Mat c;
a.copyTo(c); //a copy to c
           

3、CvMat轉Mat

//使用Mat的構造函數:Mat::Mat(const CvMat* m, bool copyData=false);	預設情況下copyData為false
CvMat* a;
//注意:以下三種效果一緻,均為淺拷貝
Mat b(a);	//a "copy" to b
Mat b(a, false);	//a "copy" to b
Mat b = a;	//a "copy" to b

//注意:當将參數copyData設為true後,則為深拷貝(複制整個圖像資料)
Mat b = Mat(a, true); //a copy to b
           

4、Mat轉CvMat

//注意:淺拷貝
Mat a;
CvMat b = a; //a "copy" to b

//注意:深拷貝
Mat a;
CvMat *b;
CvMat temp = a; //轉化為CvMat類型,而不是複制資料
cvCopy(&temp, b); //真正複制資料
           

========================IplImage與上述二者間的轉化和拷貝========================

1、IplImage之間的複制

這個不贅述了,就是cvCopy與cvCloneImage使用差別,貼張網上的圖:

OpenCV中矩陣類詳解之三:CvMat,Mat和IplImage之間的轉化和拷貝

2、IplImage轉Mat

//使用Mat的構造函數:Mat::Mat(const IplImage* img, bool copyData=false);	預設情況下copyData為false
IplImage* srcImg = cvLoadImage("Lena.jpg");
//注意:以下三種效果一緻,均為淺拷貝
Mat M(srcImg);
Mat M(srcImg, false);
Mat M = srcImg;

//注意:當将參數copyData設為true後,則為深拷貝(複制整個圖像資料)
Mat M(srcImg, true);
           

3、Mat轉IplImage

//注意:淺拷貝 - 同樣隻是建立圖像頭,而沒有複制資料
Mat M;
IplImage img = M;
IplImage img = IplImage(M);
           

4、IplImage轉CvMat

//法一:cvGetMat函數
IplImage* img;
CvMat temp;
CvMat* mat = cvGetMat(img, &temp);	//深拷貝
//法二:cvConvert函數
CvMat *mat = cvCreateMat(img->height, img->width, CV_64FC3);	//注意height和width的順序
cvConvert(img, mat);	//深拷貝
           

5、CvMat轉IplImage

//法一:cvGetImage函數
CvMat M;
IplImage* img = cvCreateImageHeader(M.size(), M.depth(), M.channels());
cvGetImage(&M, img);	//深拷貝:函數傳回img
//也可寫成
CvMat M;
IplImage* img = cvGetImage(&M, cvCreateImageHeader(M.size(), M.depth(), M.channels()));
//法二:cvConvert函數
CvMat M;
IplImage* img = cvCreateImage(M.size(), M.depth(), M.channels());
cvConvert(&M, img);	//深拷貝
           

最後注意:

1、Mat類型是自動記憶體管理,不需要顯式釋放(當然也可以手動調用release()方法強制Mat矩陣資料釋放);而CvMat則需要調用cvReleaseMat(&cvmat)來釋放,IplImage需要調用cvReleaseImage(&iplimage)來釋放。

2、建立CvMat矩陣時,第一個參數為行數,第二個參數為列數:

CvMat* cvCreateMat( int rows, int cols, int type );

3、建立IplImage圖像時,CvSize第一個參數為寬度,即列數;第二個參數為高度,即行數:

IplImage* cvCreateImage(CvSize size, int depth, int channels );

CvSize cvSize( int width, int height );

4、IplImage内部buffer每行是按4位元組對齊的,CvMat沒有這個限制。