opencv数据容器Mat,cvMat和IplImage

来源:互联网 发布:v2ex java代码 编辑:程序博客网 时间:2024/05/22 17:19

opencv中常见的与图像操作有关的数据容器有Mat,cvMat和IplImage,这三种类型都可以代表和显示图像,但是,Mat类型侧重于计算,数学性较高,openCV对Mat类型的计算也进行了优化。而CvMat和IplImage类型更侧重于“图像”,opencv对其中的图像操作(缩放、单通道提取、图像阈值操作等)进行了优化。在opencv2.0之前,opencv是完全用C实现的,但是,IplImage类型与CvMat类型的关系类似于面向对象中的继承关系。实际上,CvMat之上还有一个更抽象的基类----CvArr,这在源代码中会常见。

1. IplImage

opencv中的图像信息头,该结构体定义:

typedef struct _IplImage {  int nSize;  int ID;  int nChannels;  int alphaChannel;  int depth;   char colorModel[4];  char channelSeq[4];  int dataOrder;  int origin;  int align;   int width;  int height;   struct _IplROI *roi;  struct _IplImage *maskROI;  void *imageId;  struct _IplTileInfo *tileInfo;   int imageSize;  char *imageData;  int widthStep;  int BorderMode[4];  int BorderConst[4];   char *imageDataOrigin;  } IplImage;

dataOrder中的两个取值:交叉存取颜色通道是颜色数据排列将会是BGRBGR...的交错排列。分开的颜色通道是有几个颜色通道就分几个颜色平面存储。roi是IplROI结构体,该结构体包含了xOffset,yOffset,height,width,coi成员变量,其中xOffset,yOffset是x,y坐标,coi代表channel of interest(感兴趣的通道),非0的时候才有效。访问图像中的数据元素,分间接存储和直接存储,当图像元素为浮点型时,(uchar *) 改为 (float *):

IplImage* img=cvLoadImage("lena.jpg", 1);CvScalar s; s=cvGet2D(img,i,j); cvSet2D(img,i,j,s);   IplImage* img; //malloc memory by cvLoadImage or cvCreateImagefor(int row = 0; row < img->height; row++){ for (int col = 0; col < img->width; col++){b = CV_IMAGE_ELEM(img, UCHAR, row, col * img->nChannels + 0); g = CV_IMAGE_ELEM(img, UCHAR, row, col * img->nChannels + 1); r = CV_IMAGE_ELEM(img, UCHAR, row, col * img->nChannels + 2);}}  IplImage* img; //malloc memory by cvLoadImage or cvCreateImageuchar b, g, r; // 3 channelsfor(int row = 0; row < img->height; row++){ for (int col = 0; col < img->width; col++){b = ((uchar *)(img->imageData + row * img->widthStep))[col * img->nChannels + 0]; g = ((uchar *)(img->imageData + row * img->widthStep))[col * img->nChannels + 1]; r = ((uchar *)(img->imageData + row * img->widthStep))[col * img->nChannels + 2];}}

初始化使用IplImage *,是一个指向结构体IplImage的指针:

IplImage * cvLoadImage(const char * filename, int iscolor CV_DEFAULT(CV_LOAD_IMAGE_COLOR)); //load images from specified image IplImage * cvCreateImage(CvSize size, int depth, int channels); //allocate memory 
 
 

2.CvMat

首先,我们需要知道,第一,在OpenCV中没有向量(vector)结构。任何时候需要向量,都只需要一个列矩阵(如果需要一个转置或者共轭向量,则需要一个行矩阵)。第二,OpenCV矩阵的概念与我们在线性代数课上学习的概念相比,更抽象,尤其是矩阵的元素,并非只能取简单的数值类型,可以是多通道的值。CvMat 的结构:

typedef struct CvMat {  int type;  int step;  int* refcount; union {uchar* ptr; short* s; int* i; float* fl; double* db;} data; union { int rows; int height;};union { int cols;  int width;};} CvMat;  

创建CvMat数据:
CvMat * cvCreateMat(int rows, int cols, int type); CV_INLine CvMat cvMat((int rows, int cols, int type, void* data CV_DEFAULT); CvMat * cvInitMatHeader(CvMat * mat, int rows, int cols, int type, void * data CV_DEFAULT(NULL), int step CV_DEFAULT(CV_AUTOSTEP));  

对矩阵数据进行访问:
cvmSet( CvMat* mat, int row, int col, double value);cvmGet( const CvMat* mat, int row, int col );  CvScalar cvGet2D(const CvArr * arr, int idx0, int idx1); //CvArr只作为函数的形参void cvSet2D(CvArr* arr, int idx0, int idx1, CvScalar value);   CvMat * cvmat = cvCreateMat(4, 4, CV_32FC1);cvmat->data.fl[row * cvmat->cols + col] = (float)3.0;  CvMat * cvmat = cvCreateMat(4, 4, CV_64FC1);cvmat->data.db[row * cvmat->cols + col] = 3.0; CvMat * cvmat = cvCreateMat(4, 4, CV_64FC1);CV_MAT_ELEM(*cvmat, double, row, col) = 3.0;    if (CV_MAT_DEPTH(cvmat->type) == CV_32F)CV_MAT_ELEM_CN(*cvmat, float, row, col * CV_MAT_CN(cvmat->type) + ch) = (float)3.0; // ch为通道值if (CV_MAT_DEPTH(cvmat->type) == CV_64F)CV_MAT_ELEM_CN(*cvmat, double, row, col * CV_MAT_CN(cvmat->type) + ch) = 3.0; // ch为通道值    for (int row = 0; row < cvmat->rows; row++){ p = cvmat ->data.fl + row * (cvmat->step / 4); for (int col = 0; col < cvmat->cols; col++) { *p = (float) row + col; *(p+1) = (float)row + col + 1; *(p+2) = (float)row + col + 2; p += 3; }} CvMat * vector = cvCreateMat(1,3, CV_32SC2);CV_MAT_ELEM(*vector, CvPoint, 0, 0) = cvPoint(100,100); CvMat * vector = cvCreateMat(1,3, CV_64FC4);CV_MAT_ELEM(*vector, CvScalar, 0, 0) = CvScalar(0, 0, 0, 0);

复制矩阵操作:
CvMat* M1 = cvCreateMat(4,4,CV_32FC1);CvMat* M2;M2=cvCloneMat(M1);

3.Mat

Mat是opencv2.0推出的处理图像的新的数据结构,现在越来越有趋势取代之前的cvMat和lplImage,相比之下Mat最大的好处就是能够更加方便的进行内存管理,不再需要程序员手动管理内存的释放。opencv2.3中提到Mat是一个多维的密集数据数组,可以用来处理向量和矩阵、图像、直方图等等常见的多维数据。

class CV_EXPORTS Mat{  public:     int flags;(Note :目前还不知道flags做什么用的) int dims;  int rows,cols; uchar *data;  int * refcount;  ... };

从以上结构体可以看出Mat也是一个矩阵头,默认不分配内存,只是指向一块内存(注意读写保护)。初始化使用create函数或者Mat构造函数,以下整理自opencv2.3.1 Manual:
Mat(nrows, ncols, type, fillValue]); M.create(nrows, ncols, type);
例子:

Mat M(7,7,CV_32FC2,Scalar(1,3)); M.create(100, 60, CV_8UC(15));    int sz[] = {100, 100, 100}; Mat bigCube(3, sz, CV_8U, Scalar:all(0));  double m[3][3] = {{a, b, c}, {d, e, f}, {g, h, i}};Mat M = Mat(3, 3, CV_64F, m).inv(); Mat img(Size(320,240),CV_8UC3); Mat img(height, width, CV_8UC3, pixels, step);   IplImage* img = cvLoadImage("greatwave.jpg", 1);Mat mtx(img,0); // convert IplImage* -> Mat;  

访问Mat的数据元素:
Mat M;M.row(3) = M.row(3) + M.row(5) * 3;   Mat M1 = M.col(1);M.col(7).copyTo(M1);   Mat M;M.at<double>(i,j); M.at(uchar)(i,j); Vec3i bgr1 = M.at(Vec3b)(i,j) Vec3s bgr2 = M.at(Vec3s)(i,j) Vec3w bgr3 = M.at(Vec3w)(i,j)    double sum = 0.0f; for(int row = 0; row < M.rows; row++){  const double * Mi = M.ptr<double>(row);  for (int col = 0; col < M.cols; col++) sum += std::max(Mi[j], 0.);}   double sum=0;MatConstIterator<double> it = M.begin<double>(), it_end = M.end<double>(); for(; it != it_end; ++it) sum += std::max(*it, 0.);

Mat可进行Matlab风格的矩阵操作,如初始化的时候可以用initializers,zeros(), ones(), eye(). 除以上内容之外,Mat还有有3个重要的方法:
Mat mat = imread(const String* filename); // 读取图像imshow(const string frameName, InputArray mat); // 显示图像imwrite (const string& filename, InputArray img); //储存图像 

4. CvMat, Mat, IplImage之间的互相转换
IpIImage -> CvMat
 
CvMat matheader;CvMat * mat = cvGetMat(img, &matheader); CvMat * mat = cvCreateMat(img->height, img->width, CV_64FC3);cvConvert(img, mat)
 
IplImage -> Mat
 Mat::Mat(const IplImage* img, bool copyData=false);
 
 
 
例子:IplImage* iplImg = cvLoadImage("greatwave.jpg",1);Mat mtx(iplImg); 
   
 Mat -> IplImageMat MIplImage iplimage = M;
 CvMat -> MatMat::Mat(const CvMat* m, bool copyData=false);  
 Mat -> CvMat例子(假设Mat类型的imgMat图像数据存在):CvMat cvMat = imgMat;/*Mat -> CvMat, 类似转换到IplImage,不复制数据只创建矩阵头 
-------------------------------------------------------------------
一、Mat类型:矩阵类型,Matrix。

在openCV中,Mat是一个多维的密集数据数组。可以用来处理向量和矩阵、图像、直方图等等常见的多维数据。

Mat有3个重要的方法:

1、Mat mat = imread(constString*filename);读取图像

2、imshow(const string frameName,InputArraymat);显示图像

3、imwrite (const string&filename,InputArrayimg); 储存图像

Mat类型较CvMat与IplImage类型来说,有更强的矩阵运算能力,支持常见的矩阵运算。在计算密集型的应用当中,将CvMat与IplImage类型转化为Mat类型将大大减少计算时间花费。

A.Mat -> IplImage

同样只是创建图像头,而没有复制数据。

例: // 假设Mat类型的imgMat图像数据存在

IplImage pImg= IplImage(imgMat);

B.Mat -> CvMat

与IplImage的转换类似,不复制数据,只创建矩阵头。

例: // 假设Mat类型的imgMat图像数据存在

CvMat cvMat = imgMat;

二、CvMat类型与IplImage类型:“图像”类型

在openCV中,Mat类型与CvMat和IplImage类型都可以代表和显示图像,但是,Mat类型侧重于计算,数学性较高,openCV对Mat类型的计算也进行了优化。而CvMat和IplImage类型更侧重于“图像”,openCV对其中的图像操作(缩放、单通道提取、图像阈值操作等)进行了优化。

补充:IplImageCvMat派生,而CvMatCvArr派生即CvArr->CvMat-> IplImage

CvArr用作函数的参数,无论传入的是CvMatIplImage,内部都是按CvMat处理。

1.CvMat

A.CvMat-> IplImage

IplImage* img = cvCreateImage(cvGetSize(mat),8,1);
cvGetImage(matI,img);

cvSaveImage("rice1.bmp",img);

B.CvMat->Mat

与IplImage的转换类似,可以选择是否复制数据。

Mat::Mat(const CvMat* m, bool copyData=false);

在openCV中,没有向量(vector)的数据结构。任何时候,但我们要表示向量时,用矩阵数据表示即可。

但是,CvMat类型与我们在线性代数课程上学的向量概念相比,更抽象,比如CvMat的元素数据类型并不仅限于基础数据类型,比如,下面创建一个二维数据矩阵:

CvMat* cvCreatMat(int rows ,int cols , int type);

这里的type可以是任意的预定义数据类型,比如RGB或者别的多通道数据。这样我们便可以在一个CvMat矩阵上表示丰富多彩的图像了。

2.IplImage

在类型关系上,我们可以说IplImage类型继承自CvMat类型,当然还包括其他的变量将之解析成图像数据。

IplImage类型较之CvMat多了很多参数,比如depth和nChannels。在普通的矩阵类型当中,通常深度和通道数被同时表示,如用32位表示RGB+Alpha.但是,在图像处理中,我们往往将深度与通道数分开处理,这样做是OpenCV对图像表示的一种优化方案。

IplImage的对图像的另一种优化是变量origin----原点。在计算机视觉处理上,一个重要的不便是对原点的定义不清楚,图像来源,编码格式,甚至操作系统都会对原地的选取产生影响。为了弥补这一点,openCV允许用户定义自己的原点设置。取值0表示原点位于图片左上角,1表示左下角。

dataOrder参数定义数据的格式。有IPL_DATA_ORDER_PIXEL和IPL_DATA_ORDER_PLANE两种取值,前者便是对于像素,不同的通道的数据交叉排列,后者表示所有通道按顺序平行排列。

IplImage类型的所有额外变量都是对“图像”的表示与计算能力的优化。

A.IplImage -> Mat

IplImage* pImg = cvLoadImage("lena.jpg");
Mat img(pImg,0); // 0是不複製影像,也就是pImgimgdata共用同個記憶體位置,header各自有
B.IplImage -> CvMat

1CvMatmathdr,*mat= cvGetMat( img, &mathdr );

法2CvMat *mat = cvCreateMat(img->height,img->width,CV_64FC3 );
cvConvert( img, mat );

C.IplImage*-> BYTE*

BYTE* data= img->imageData;

CvMat和IplImage创建时的一个小区别:

1、建立矩阵时,第一个参数为行数,第二个参数为列数。

CvMat* cvCreateMat( int rows, int cols, int type );

2、建立图像时,CvSize第一个参数为宽度,即列数;第二个参数为高度,即行数。这 个和CvMat矩阵正好相反。

IplImage* cvCreateImage(CvSize size, int depth, int channels );

CvSize cvSize( int width, int height );

IplImage内部buffer每行是按4字节对齐的,CvMat没有这个限制

补充:

A.BYTE*-> IplImage*

img= cvCreateImageHeader(cvSize(width,height),depth,channels);

cvSetData(img,data,step);

//首先由cvCreateImageHeader()创建IplImage图像头,制定图像的尺寸,深度和通道数;

//然后由cvSetData()根据BYTE*图像数据指针设置IplImage图像头的数据数据,

//其中step指定该IplImage图像每行占的字节数,对于1通道的IPL_DEPTH_8U图像,step可以等于width

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 我情人天天说没时间出去该怎么办 两个月宝宝下体三角区肿了怎么办 夏养的龙猫家里有味怎么办 不小心踩到仓鼠吐血了怎么办 不小心踩到仓鼠的头怎么办 母仓鼠生完孩子特别暴躁怎么办 被仓鼠咬出血怎么办要不要打针 被小仓鼠咬出血了该怎么办 仓鼠咬破手指流血了该怎么办 小仓鼠的手被棉花丝绑住了怎么办 荷兰猪如果不小心撞流血了怎么办 帮同事刷杯子但把杯子弄坏了怎么办 贵宾犬喜欢张开嘴巴跟人玩怎么办 鼻烟放了几天感觉跟受潮一样怎么办 两个月宝宝鼻屎堵住鼻子怎么办 肉包着智齿怎么办洗燥电影完整版 大腿内侧突然长黑痣越来越大怎么办 肚脐发炎、不脱落怎么办_妈网百科 老公出轨找个按摩的还不离婚怎么办 别人拿错钥匙装修好了房子怎么办 撞车后对方全责却不赔钱怎么办 我的世界国服客户端都是英文怎么办 下载的3d模型没有材质怎么办 写字时习惯把本子放歪该怎么办 被蚊子咬后留下硬疙瘩怎么办 吃冰镇西瓜导致呼吸不顺怎么办 吃冰镇西瓜嚓气导致呼吸不顺怎么办 在pr里面找不到做字幕的怎么办 电脑主机电源坏了接口坏了怎么办 邻居捡到我手机不给这种情况怎么办 婆婆总在儿子面前说媳妇坏话怎么办 试管准备取卵雌激素低该怎么办 订了火车票了忘记带身份证怎么办 网上买火车票忘记带身份证了怎么办 网上买的火车票忘记带身份证怎么办 深圳东站不卖站台票要送客怎么办 网吧刷身份证机器突然不好使怎么办 买了个衣服穿起来有点老气怎么办 美股主动退市股票钱怎么办 新注册的微信号被实名认证了怎么办 他出轨对我冷暴力孩子小怎么办