在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;
对矩阵的操作
对矩阵的操作,
//创建矩阵,分配矩阵空间,
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++的接口
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;
}