在OpenCV中,矩陣是一個基礎的數據結構,在CvCore中。在較早版本里面,使用的是C語言實現的struct,較新的版本里面有C++實現的class。下面分別介紹一下這兩種使用方法。
CvMat
參考http://www.opencv.org.cn/index.php/Cxcore%E5%9F%BA%E7%A1%80%E7%BB%93%E6%9E%84
在OpenCV的中文首頁上,文檔里面給的還是C實現的結構體。如下,
typedef struct CvMat { int type; /* CvMat 標識 (CV_MAT_MAGIC_VAL), 元素類型和標記 */ int step; /* 以字節為單位的行數據長度*/ int* refcount; /* 數據引用計數 */ union { uchar* ptr; short* s; int* i; float* fl; double* db; } data; /* data 指針 */ #ifdef __cplusplus union { int rows; int height; }; union { int cols; int width; }; #else int rows; /* 行數 */ int cols; /* 列數*/ #endif } CvMat;
對矩陣的操作,參考,http://blog.csdn.net/schoolers/article/details/4758838
對矩陣的操作,
//創建矩陣,分配矩陣空間, CvMat* cvCreateMat(int rows, int cols, int type); // type: 矩陣元素類型. 格式為CV_<bit_depth>(S|U|F)C<number_of_channels>. // 例如: CV_8UC1 表示8位無符號單通道矩陣, CV_32SC2表示32位有符號雙通道矩陣. //釋放矩陣空間, CvMat* M = cvCreateMat(4,4,CV_32FC1); cvReleaseMat(&M); //可以從數組創建矩陣, double a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }; CvMat Ma=cvMat(3, 4, CV_64FC1, a); //存取矩陣元素, //二維浮點數矩陣, //間接存取 cvmSet(M,i,j,2.0); // Set M(i,j) t = cvmGet(M,i,j); // Get M(i,j) //直接存取, CvMat* M = cvCreateMat(4,4,CV_32FC1); int n = M->cols; float *data = M->data.fl; data[i*n+j] = 3.0; //用數組初始化矩陣的時候,可以直接操作數組, double a[16]; CvMat Ma = cvMat(3, 4, CV_64FC1, a); a[i*4+j] = 2.0; // Ma(i,j)=2.0;
對於矩陣的其它操作,比如加減乘除,SVD分解等,這里略去。
下面是使用C++的接口,參考http://opencv.willowgarage.com/documentation/cpp/core_basic_structures.html

class CV_EXPORTS Mat { public: // ... a lot of methods ... ... /*! includes several bit-fields: - the magic signature - continuity flag - depth - number of channels */ int flags; //! the array dimensionality, >= 2 int dims; //! the number of rows and columns or (-1, -1) when the array has more than 2 dimensions int rows, cols; //! pointer to the data uchar* data; //! pointer to the reference counter; // when array points to user-allocated data, the pointer is NULL int* refcount; // other members ... };
//創建矩陣,可以使用構造函數,如下, Mat::Mat() Mat::Mat(int rows, int cols, int type) //如果初始化的時候沒有傳入size的參數,或者后面需要改變size的參數,可以使用create來調整。 create(nrows, ncols, type) //如下, // make 7x7 complex matrix filled with 1+3j. cv::Mat M(7,7,CV_32FC2,Scalar(1,3)); // and now turn M to 100x60 15-channel 8-bit matrix. // The old content will be deallocated M.create(100,60,CV_8UC(15)); //釋放資源,可以使用 release()成員函數。 //也可以使用一維或多維數組來初始化矩陣, double m[3][3] = {{a, b, c}, {d, e, f}, {g, h, i}}; cv::Mat M = cv::Mat(3, 3, CV_64F, m); //元素的訪問, template<typename T> T& Mat::at(int i, int j) template<typename T> const T& Mat::at(int i, int j) const template<typename T> T& Mat::at(int i, int j, int k) template<typename T> const T& Mat::at(int i, int j, int k) const // i, j, k – Indices along the dimensions 0, 1 and 2, respectively //在矩陣是行向量或列向量的時候,也可以只用一個參數來訪問元素。 //類似於C++里面的迭代器,Mat也可以使用iterator。
另外有兩個問題稍作討論,
cvCreateMat的使用,
void Create(CvMat*& mat,int rows,int cols) //void Create(CvMat* mat,int rows,int cols) { mat = cvCreateMat(rows,cols,CV_32FC1); }
一開始使用的是注釋掉的那一行,在調用這個函數之后,mat本應該被初始化的,但在后面的訪問中會出現問題,后來將參數改為指針引用,才解決錯誤。
另一個問題是C++里面矩陣的定義是cv::mat,但在很多舊的函數里面,要求傳入的參數是CvMat*,如何進行轉換呢?
這里很多都只適用於2維矩陣,對於多維的矩陣,OpenCV也是支持的。OpenCV里面矩陣的大小為rows*cols,但在每個位置,由channel控制這個點的維數。比如復數矩陣,這個點可以用2個channels來表示一個復數。元素訪問的時候可以使用i,j,k三個參數。
參考,http://stackoverflow.com/questions/1824787/opencv-multi-channel-element-access
或者在定義數據類型的時候,不是使用CV_32FC3之類的,而是自定義類型,比如
struct elem{ double f1; doubel f2; }
那么就可以先訪問到elem,然后再通過elem訪問f1和f2.
就這么多吧,隨便整理的一些,沒有辦法靜下來好好整理。
一個簡單的實例程序如下,
// test for cvCreateMat #include "cxcore.h" #include <cstdio> //void Create(CvMat*& mat,int rows,int cols) void Create(CvMat*& mat,int rows,int cols) { mat = cvCreateMat(rows,cols,CV_32FC1); } void Init(CvMat* mat) { int i=0,j=0,k=0; int rows = mat->rows; int cols = mat->cols; for(i=0;i<rows;i++) { for(j=0;j<cols;j++) { cvmSet(mat,i,j,i+1.0*j/10); } } } void Print(CvMat* mat) { int i=0,j=0,k=0; int rows = mat->rows; int cols = mat->cols; float tm = 0; for(i=0;i<rows;i++) { for(j=0;j<cols;j++) { tm = cvmGet(mat,i,j); printf("%4g ",tm); } printf("\n"); } } int main() { CvMat* mat; Create(mat,4,5); Init(mat); Print(mat); return 0; }