在开始学习矩阵的相关内容之前,我们需要知道两件事情。第一,在OpenCV中没有向量(vector)结构。任何时候需要向量,都只需要一个列矩阵(如果需要一个转置或者共轭向量,则需要一个行矩阵)。第二,OpenCV矩阵的概念与我们在线性代数课上学习的概念相比,更抽象,尤其是矩阵的元素,并非只能取简单的数值类型。例如,一个用于新建一个二维矩阵的例程具有以下原型:
- cvMat* cvCreateMat ( int rows, int cols, int type );
这里type可以是任何预定义类型,预定义类型的结构如下:CV_<bit_depth> (S|U|F)C<number_of_channels>。于是,矩阵的元素可以是32位浮点型数据(CV_32FC1),或者是无符号的8位三元组的整型数据(CV_8UC3),或者是无数的其他类型的元素。一个CvMat的元素不一定就是个单一的数字。在矩阵中可以通过单一(简单)的输入来表示多值,这样我们可以在一个三原色图像上描绘多重色彩通道。对于一个包含RGB通道的简单图像,大多数的图像操作将分别应用于每一个通道(除非另有说明)。
实质上,正如例3-1所示,CvMat的结构相当简单,(可以自己打开文件…/opencv/cxcore/include/cxtypes.h查看)。矩阵由宽度(width)、高度(height)、类型(type)、行数据长度(step,行的长度用字节表示而不是整型或者浮点型长度)和一个指向数据的指针构成(现在我们还不能讨论更多的东西)。可以通过一个指向CvMat的指针访问这些成员,或者对于一些普通元素,使用现成的访问方法。例如,为了获得矩阵的大小,可通过调用函数vGetSize(CvMat*),返回一个CvSize结构,便可以获取任何所需信息,或者通过独立访问高度和宽度,结构为matrix->height 和matrix->width。 【33~34】
例3-1:CvMat结构:矩阵头
- typedef struct CvMat {
- int type;
- int step;
- int* refcount; // for internal use only
- union {
- uchar* ptr;
- short* s;
- int* i;
- float* fl;
- double* db;
- } data;
- union {
- int rows;
- int height;
- };
- union {
- int cols;
- int width;
- };
- } CvMat;
此类信息通常被称作矩阵头。很多程序是区分矩阵头和数据体的,后者是各个data成员所指向的内存位置。
矩阵有多种创建方法。最常见的方法是用cvCreateMat(),它由多个原函数组成,如cvCreateMatHeader()和cvCreateData()。cvCreateMatHeader()函数创建CvMat结构,不为数据分配内存,而cvCreateData()函数只负责数据的内存分配。有时,只需要函数cvCreateMatHeader(),因为已因其他理由分配了存储空间,或因为还不准备分配存储空间。第三种方法是用函数cvCloneMat (CvMat*) ,它依据一个现有矩阵创建一个新的矩阵。当这个矩阵不再需要时,可以调用函数cvReleaseMat(CvMat*)释放它。 【34】
例3-2概述了这些函数及其密切相关的其他函数。
例3-2:矩阵的创建和释放
- //Create a new rows by cols matrix of type 'type'.
- //
- CvMat* cvCreateMat( int rows, int cols, int type );
- //Create only matrix header without allocating data
- //
- CvMat* cvCreateMatHeader( int rows, int cols, int type );
- //Initialize header on existiong CvMat structure
- //
- CvMat* cvInitMatHeader(
- CvMat* mat,
- int rows,
- int cols,
- int type,
- void* data = NULL,
- int step = CV_AUTOSTEP
- );
- //Like cvInitMatHeader() but allocates CvMat as well.
- //
- CvMat cvMat(
- int rows,
- int cols,
- int type,
- void* data = NULL
- );
- //Allocate a new matrix just like the matrix 'mat'.
- //
- CvMat* cvCloneMat( const cvMat* mat );
- // Free the matrix 'mat', both header and data.
- //
- void cvReleaseMat( CvMat** mat );
与很多OpenCV结构类似,有一种构造函数叫cvMat,它可以创建CvMat结构,但实际上不分配存储空间,仅创建头结构(与cvInitMatHeader()类似)。这些方法对于存取到处散放的数据很有作用,可以将矩阵头指向这些数据,实现对这些数据的打包,并用操作矩阵的函数去处理这些数据,如例3-3所示。
例3-3:用固定数据创建一个OpenCV矩阵
一旦我们创建了一个矩阵,便可用它来完成很多事情。最简单的操作就是查询数组定义和数据访问等。为查询矩阵,我们可以使用函数cvGetElemType(const CvArr* arr),cvGetDims(const CvArr* arr, int* sizes=NULL)和cvGet- DimSize(const CvArr* arr,int index)。第一个返回一个整型常数,表示存储在数组里的元素类型(它可以为CV_8UC1和CV_64FC4等类型)。第二个取出数组以及一个可选择的整型指针,它返回维数(我们当前的实例是二维,但是在后面我们将遇到的N维矩阵对象)。如果整型指针不为空,它将存储对应数组的高度和宽度(或者N维数)。最后的函数通过一个指示维数的整型数简单地返回矩阵在那个维数上矩阵的大小。
- //Create an OpenCV Matrix containing some fixed data.
- //
- float vals[] = { 0.866025, -0.500000, 0.500000, 0.866025 };
- CvMat rotmat;
- cvInitMatHeader(
- &rotmat,
- 2,
- 2,
- CV_32FC1,
- vals
- );