当使用OpenCV时,你会经常使用IplImage类型,该类型是OpenCV的基础图像类型。图像可能是灰度图,彩色图,四通道图(RGB+Alpha)等,而每个通道可能是整数或浮点数类型。OpenCV提供了对图像的大量处理操作函数。
在我们讨论IplImage之前,我们需要看另一个数据类型:CvMat,即OpenCV的矩阵类型。尽管OpenCV是用C语言实现的,但是CvMat和IplImage的关系其实就类似于C++中的类的继承关系。IplImage类继承自CvMat类。所以,我们最好先了解一下IplImage的基类CvMat类的情况,然后再看更复杂的IplImage类。而CvArr类,是CvMat类的抽象基类。正因为CvArr类是基类,所以当我们看到OpenCV的函数参数为CvArr*类型的参数时,我们可以代入CvMat*或者IplImage*类型的实参。
CvMat矩阵数据结构
当我们学习CvMat之前,我们必须知道两个事情,首先OpenCV中是没有"vector(向量)"数据类型的,当我们需要一个"vector"时,我们就使用一个三行一列的矩阵。其次,OpenCV中矩阵的概念比线性代数中矩阵的概念更抽象和复杂一些一些。例如,创建矩阵的函数:CvMat* cvCreateMat(int rows,int cols,int type),其中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来获得矩阵的尺寸。
#include"iostream" using namespace std; #include<cv.h> #include<cxcore.h> #include<highgui.h> void cmp(CvMat *mat) { CvScalar value; value = cvScalarAll(2.0); float temp[9]; CvMat dst = cvMat(3,3,CV_32FC1,temp); cvSubS(mat,value,&dst); cout<<"source"<<endl; for(int i=0;i<mat->rows;i++) { for(int j=0;j<mat->cols;j++) cout<<CV_MAT_ELEM(*mat,float,i,j)<<" "; cout<<endl; } cout<<"dst"<<endl; for(int i=0;i<dst.rows;i++) { for(int j=0;j<dst.cols;j++) cout<<CV_MAT_ELEM(dst,float,i,j)<<" "; cout<<endl; } } int main() { float a[] = { 2.6,2.5,3.3, 1.5,3.5,5.5, 8.7,4.5,6.0 }; double c[9]; CvMat* mat_01,*mat_02; mat_01 = cvCreateMat(3,3,CV_32FC1); //可以对直接赋值,因为已经分配了空间 for(int i=0;i<mat_01->rows;i++) { for(int j=0;j<mat_01->cols;j++) if(i==j) cvmSet(mat_01,i,j,1.0); else cvmSet(mat_01,i,j,0.0); cout<<endl; } cmp(mat_01); mat_02 = cvCreateMatHeader(3,3,CV_8UC1); //在初始化前不可以直接赋值,因为没有分配数据空间 cvInitMatHeader(mat_02,3,3,CV_32FC1,a); CvMat mat_03 = cvMat(3,3,CV_32FC1,c); //调用构造函数生成矩阵 cvMatMulAdd( mat_01, mat_02, 0, &mat_03 ); for(int i=0;i<mat_03.rows;i++) { for(int j=0;j<mat_03.cols;j++) cout<<CV_MAT_ELEM(mat_03,float,i,j)<<" "; cout<<endl; } system("pause"); return 1; }
可以认为有三种初始化方式:
1.分配数据空间但未给数据 cvCreateMat;
2.不分配数据空间 cvCreateMatHeader();
3.分配空间并且初始化数据,cvMat.