OpenCV(1)——基础数据结构CvMat
在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; }