opencv的基本数据结构
结构 | 成员 | 意义 |
---|---|---|
CvPoint | int x,y | 图像中的点 |
CvPoint2D32f | float x,y | 二维空间中的点 |
CvPoint3D32f | float x,y,z | 三维空间中的点 |
CvSize | int width,height | 图像的尺寸 |
CvRect | int x,y,width,height | 图像的部分区域 |
CvScalar | double val[4] | RGBA值 |
Mat 数据结构
- Mat类型侧重于计算,数学性较高,openCV对Mat类型的计算也进行了优化。而CvMat和IplImage类型更侧重于“图像”,opencv对其中的图像操作(缩放、单通道提取、图像阈值操作等)进行了优化。在opencv2.0之前,opencv是完全用C实现的,但是,IplImage类型与CvMat类型的关系类似于面向对象中的继承关系。实际上,CvMat之上还有一个更抽象的基类----CvArr,这在源代码中会常见。
- Mat是opencv2.0推出的处理图像的新的数据结构,现在越来越有趋势取代之前的cvMat和lplImage,相比之下Mat最大的好处就是能够更加方便的进行内存管理,不再需要程序员手动管理内存的释放
- IplImage,CvMat,Mat的关系参考
Mat的结构,是一个类,本身就带有很多的函数,成员,重载
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也是一个矩阵头,,由两个数据部分组成:矩阵头(包含矩阵尺寸,存储方法,存储地址等信息)和一个指向存储所有像素值的矩阵(根据所选存储方法的不同矩阵可以是不同的维数)的指针。默认不分配内存,只是指向一块内存(注意读写保护)。
但矩阵本身的尺寸会依图像的不同而不同,通常比矩阵头的尺寸大数个数量级。因此,当在程序中传递图像并创建拷贝时,大的开销是由矩阵造成的,而不是信息头。
为了搞定这个问题,OpenCV使用引用计数机制。其思路是让每个 Mat 对象有自己的信息头,但共享同一个矩阵。这通过让矩阵指针指向同一地址而实现。而拷贝构造函数则 只拷贝信息头和矩阵指针 ,而不拷贝矩阵。
初始化使用
create
函数或者Mat构造函数
但某些时候你仍会想拷贝矩阵本身(不只是信息头和矩阵指针),这时可以使用函数
clone()
或者copyTo()
。
/*CV_32FC2的定义:*/
CV_[The number of bits per item][Signed or Unsigned][Type Prefix]C[The channel number]
初始化例子
Mat(nrows, ncols, type, fillValue);
M.create(nrows, ncols, type);
初始化:
Mat M(7,7,CV_32FC2,Scalar(1,3)); /*创建复数矩阵1+3j*/
M.create(100, 60, CV_8UC(15)); /*创建15个通道的8bit的矩阵*/
/*创建100*100*100的8位数组*/
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); /*const unsigned char* pixels,int width, int height, int step*/
/*使用现成图像初始化Mat*/
IplImage* img = cvLoadImage("greatwave.jpg", 1);
Mat mtx(img); // convert IplImage* -> Mat; /*不复制数据,只创建一个数据头*/
CvMat的结构 ,只是一个数据结构,很多的实现要借助与其他的函数
typedef struct CvMat{
int type;
int step;
int* refcount;
union{
uchar* ptr;
short* s;
int* i;
float *f1;
double* db;
} data;
union{
int rows;
int height;
};
union{
int cols;
int width;
};
}CvMat;
矩阵的创建和释放
CvMat* cvCreateMat( int rows, int cols, int type ); //创建一个矩阵
CvMat* cvCreateMatHeader( int rows, int cols, int type ); //创建一个矩阵结构,不分配空间
CvMat* cvInitMatHeader(CvMat* mat,int rows,int cols,int type,void* data = NULL,int step = CV_AUTOSTEP);//用一个现有矩阵初始化矩阵
CvMat cvMat(int rows,int cols,int type,void* data = NULL);//初始化矩阵结构,不分配空间
CvMat* cvCloneMat( const cvMat* mat );//复制一个mat副本
void cvReleaseMat( CvMat** mat ); //释放矩阵
CvMat, Mat, IplImage之间的互相转换
IpIImage -> CvMat
/*cvGetMat*/
CvMat matheader;
CvMat * mat = cvGetMat(img, &matheader);
/*cvConvert*/
CvMat * mat = cvCreateMat(img->height, img->width, CV_64FC3);
cvConvert(img, mat)
IplImage -> Mat
Mat::Mat(const IplImage* img, bool copyData=false);/*default copyData=false,与原来的IplImage共享数据,只是创建一个矩阵头*/
例子:
IplImage* iplImg = cvLoadImage("greatwave.jpg", 1);
Mat mtx(iplImg); /* IplImage * -> Mat,共享数据; or : Mat mtx = iplImg;*/
Mat -> IplImage
Mat M
IplImage iplimage = M; /*只创建图像头,不复制数据*/
CvMat -> Mat
Mat::Mat(const CvMat* m, bool copyData=false); /*类似IplImage -> Mat,可选择是否复制数据*/
Mat -> CvMat
例子(假设Mat类型的imgMat图像数据存在):
CvMat cvMat = imgMat;/*Mat -> CvMat, 类似转换到IplImage,不复制数据只创建矩阵头