OpenCV中矩陣的定義

      在我們討論IplImage之前,我們需要看另一個數據類型:CvMat,即OpenCV的矩陣類型。儘管OpenCV是用C語言實現的,但是CvMat和IplImage的關係其實就類似於C++中的類的繼承關係。IplImage類繼承自CvMat類。所以,我們最好先了解一下IplImage的基類CvMat類的情況,然後再看更復雜的IplImage類。而CvArr類,是CvMat類的抽象基類。正因爲CvArr類是基類,所以當我們看到OpenCV的函數參數爲CvArr*類型的參數時,我們可以代入CvMat*或者IplImage*類型的實參。
CvMat矩陣數據結構
當我們學習CvMat之前,我們必須知道兩個事情,首先OpenCV中是沒有"vector(向量)"數據類型的,當我們需要一個"vector"時,我們就使用一個三行一列的矩陣。其次,OpenCV中矩陣的概念比線性代數中矩陣的概念更抽象和複雜一些一些。例如,創建矩陣的函數:CvMat* cvCreateMat(int rows,int cols,int type),其中type代表預定義的數據類型,即矩陣中每一個元素的數據類型,該類型的形式是:CV_<bit數>(S|U|F)C<通道數>,例如,數據類型可能是CV32FC1,即32bit的浮點數,或CV_8UC3,8bit的無符號整數,或CV_8UC3,無符號8bit整數,3通道,等等。我們會發現,cvMat裏,矩陣中行和列上的每一個元素,不必是一個單獨的數字,可能是一系列數字(有幾個通道就有幾個數字)。每一個元素可以代表多個值,就允許了我們在矩陣中包含一個RGB的圖像。
從內部的結構上看,CvMat相當的簡單,我們可以通過代碼看一下該數據結構的原型(代碼在.../opencv/cxcore/include/cxtypes.h):
其中包含了width,height,type,step(是一行元素的長度,與width類似,但以字節計算),以及指向數據的指針.你可以通過CvMat數據類型的變量直接接觸該類型內部的成員,例如,CvMat* matrix ,就可以用matrix->height,matrix->width來獲得矩陣的尺寸。又或者通過OpenCV的函數來獲得。例如,可以用cvGetSize(CvMat*)來獲得CvSize對象,這代表該矩陣的長和寬。
typedef struct CvMat
{
    int type;
    int step;

    /* for internal use only */
    int* refcount;
    int hdr_refcount;

    union
    {
        uchar* ptr;
        short* s;
        int* i;
        float* fl;
        double* db;
    } data;

#ifdef __cplusplus
    union
    {
        int rows;
        int height;
    };

    union
    {
        int cols;
        int width;
    };
#else
    int rows;
    int cols;
#endif

}
CvMat;

以上,是該CvMat類型的數據的“頭部”,即矩陣的定義部分。許多OpenCV的函數,將矩陣的頭部和數據部分分開處理。
矩陣的創建可以用多種方法,最簡單的一種是CvMat* cvCreateMat(int rows,int cols,int type),該方法既設置了矩陣的頭部,又爲數據部分分配了內存空間,該函數是cvCreateMatHeader()和cvCreateData()的合併縮寫。cvCreateMatHeader()只創建CvMat頭部,但不爲數據部分分配空間。而cvCreateData()則是爲矩陣的數據部分分配了內存空間。有時候,我們只需要cvCreateMatHeader()就可以了,因爲基於一些理由,我們可能已經爲數據部分分配了空間,或者此時分配空間還不是時候。另一個創建矩陣的方法cvCloneMat(CvMat*)是從一個已經有的矩陣,來“克隆”出一個新的矩陣來。當我們不再需要某矩陣時,我們需要調用長cvReleaseMat(CvMat*)來釋放它。
就象其他的OpenCV數據類型一樣,矩陣數據類型有一個構造函數,CvMat cvMat( int rows, int cols, int type, void* data=NULL );這個函數沒有爲矩陣的數據部分分配空間,只是初始化了矩陣的頭部,類似cvInitMatheader()。

以下是這些函數的原型:

1,CreateMat

創建矩陣

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

rows
    矩陣行數。
cols
    矩陣列數。
type
    矩陣元素類型。 通常以 CV_<比特數>(S|U|F)C<通道數>型式描述, 例如:

   CV_8UC1 意思是一個8-bit 無符號單通道矩陣, CV_32SC2 意思是一個32-bit 有符號二個通道的矩陣。

函數 cvCreateMat 爲新的矩陣分配頭和下面的數據,並且返回一個指向新創建的矩陣的指針。是下列操作的縮寫型式:

CvMat* mat = cvCreateMatHeader( rows, cols, type );
cvCreateData( mat );
矩陣按行存貯。所有的行以4個字節對齊。


2,CreateMatHeader

創建新的矩陣頭

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

rows

   矩陣行數.

cols
    矩陣列數.
type
    矩陣元素類型(見 cvCreateMat).

函數 cvCreateMatHeader 分配新的矩陣頭並且返回指向它的指針. 矩陣數據可被進一步的分配,使用cvCreateData 或通過 cvSetData明確的

分配數據.


3,ReleaseMat

刪除矩陣

void cvReleaseMat( CvMat** mat );

mat
    雙指針指向矩陣.

函數cvReleaseMat 縮減矩陣數據參考計數並且釋放矩陣頭 :

if( *mat )
    cvDecRefData( *mat );
cvFree( (void**)mat );

4,InitMatHeader

初始化矩陣頭

CvMat* cvInitMatHeader( CvMat* mat, int rows, int cols, int type,
                           void* data=NULL, int step=CV_AUTOSTEP );

mat
    指針指向要被初始化的矩陣頭.
rows
    矩陣的行數.
cols
    矩陣的列數.
type
    矩陣元素類型.
data
    可選的,將指向數據指針分配給矩陣頭.
step
    排列後的數據的整個行寬,默認狀態下,使用STEP的最小可能值。也就是說默認情況下假定矩陣的行與行之間無隙.

函數 cvInitMatHeader 初始化已經分配了的 CvMat 結構. 它可以被OpenCV矩陣函數用於處理原始數據。

例如, 下面的代碼計算通用數組格式存貯的數據的矩陣乘積.

計算兩個矩陣的積

double a[] = { 1, 2, 3, 4,
               5, 6, 7, 8,
               9, 10, 11, 12 };

double b[] = { 1, 5, 9,
               2, 6, 10,
               3, 7, 11,
               4, 8, 12 };

double c[9];
CvMat Ma, Mb, Mc ;

cvInitMatHeader( &Ma, 3, 4, CV_64FC1, a );
cvInitMatHeader( &Mb, 4, 3, CV_64FC1, b );
cvInitMatHeader( &Mc, 3, 3, CV_64FC1, c );

cvMatMulAdd( &Ma, &Mb, 0, &Mc );
// c 數組存貯 a(3x4) 和 b(4x3) 矩陣的積


5,Mat

初始化矩陣的頭

CvMat cvMat( int rows, int cols, int type, void* data=NULL );

rows
    矩陣行數
cols
    列數.
type
    元素類型(見CreateMat).
data
    可選的分配給矩陣頭的數據指針 .

函數 cvMat 是個一快速內連函數,替代函數 cvInitMatHeader. 也就是說它相當於:

CvMat mat;
cvInitMatHeader( &mat, rows, cols, type, data, CV_AUTOSTEP );

 

6,CloneMat

創建矩陣拷貝

CvMat* cvCloneMat( const CvMat* mat );

mat
    輸入矩陣.

函數 cvCloneMat 創建輸入矩陣的一個拷貝並且返回該矩陣的指針.

以下的例子中,我們讓矩陣的數據部分指向了已經分配好了的數據:

float vals[] = { 0.866025, -0.500000, 0.500000, 0.866025};
  
CvMat rotmat;
  
cvInitMatHeader(
    &rotmat,
    2,
    2,
    CV_32FC1,
    vals
);
當我們定義好了矩陣,我們可以通過一些函數查看矩陣的屬性,例如:cvGetElemType(const cvArr* arr),cvGetDims(const CvArr* arr,int*

sizes=NULL),cvGetDimSize(const CvArr* arr,index)

7.GetElemType

返回數組元素類型

int cvGetElemType( const CvArr* arr );

arr
    輸入數組.

函數 GetElemType 返回數組元素類型就像在cvCreateMat 中討論的一樣:

    CV_8UC1 ... CV_64FC4


8.GetDims, GetDimSize

返回數組維數和他們的大小或者特殊維的大小

int cvGetDims( const CvArr* arr, int* sizes=NULL );
int cvGetDimSize( const CvArr* arr, int index );

arr
    輸入數組.
sizes
    可選的輸出數組維尺寸向量,對於2D數組第一位是數組行數(高),第二位是數組列數(寬)
index
    以0爲基準的維索引下標(對於矩陣0意味着行數,1意味着列數,對於圖象0意味着高,1意味着寬。

函數 cvGetDims 返回維數和他們的大小。如果是 IplImage 或 CvMat 總是返回2,不管圖像/矩陣行數。函數 cvGetDimSize 返回特定的維大小(每維的元素數)。

以下是一個例子:
#pragma comment( lib, "cxcore.lib" )
#include "cv.h"
#include <stdio.h>
void main()
{
CvMat rotmat;
int sizes[2];
float array[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14};
//注意,此句更改爲 cvInitMatHeader(&rotmat,3,5,CV_32FC1,NULL);時,cvGetDimSize不能起作用
cvInitMatHeader(&rotmat,3,5,CV_32FC1,array);
int type = cvGetElemType(&rotmat);
cvGetDims(&rotmat,sizes);
printf("type=%d/n",type);
printf("height=%d,width=%d/n",sizes[0],sizes[1]);
printf("height=%d,width=%d/n",cvGetDimSize(&rotmat, 0),cvGetDimSize(&rotmat, 1));
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章