当我们学习CvMat之前,OpenCV中矩阵的概念比线性代数中矩阵的概念更抽象和复杂一些一些。例如,创建矩阵的函数:CvMat*cvCreateMat(int rows,int cols,inttype),其中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;
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,inttype),该方法既设置了矩阵的头部,又为数据部分分配了内存空间,该函数是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, inttype,
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(constCvArr* arr,index)