Mat类
2016-03-13 01:31
330 查看
Mat类特征
opencv2.x版本引入Mat类来替代传统的CMat lpimage等C语言结构。使用Mat对象可以不需要去手动分配和释放内存空间。
兼容C,除非从事嵌入式系统,否则没必要再去用lpimage等C语言结构。
如果传递一个已经分配内存的的Mat对象,则会被拒绝(传递对象而不是指针将给形参分配内存)。使用Mat类将使得尽可能少的使用内存空间来达到目标。
Mat类分为两部分:
1)矩阵头:包含矩阵大小,图像存储方式(维度),存储的位置信息(如单通道还是多通道)等信息;
2)指向矩阵的指针(* data);
opencv是一个图像处理库,包含很多处理函数,通常会调用很多函数去实现目标,那么,传递图像数据给函数将是一种常态动作。
在opencv当中,每个mat对象都有自己的矩阵头,而data指针指向的数据是可以共享的。比如如下:
Mat A, C; // creates just the header parts A = imread(argv[1], CV_LOAD_IMAGE_COLOR); // here we'll know the method used (allocate matrix) Mat B(A); // Use the copy constructor C = A; // Assignment operator //通过A构造的B C对象和A对象共享一个矩阵数据区
以上的A B C对象拥有各自的矩阵头,但是共享一个矩阵数据,修改任何一个对象都会导致另2个同步变化。
有趣的是,你可以仅仅使用矩阵数据的一部分来手动创建一个Mat对象:
Mat D (A, Rect(10, 10, 100, 100) ); // using a rectangle Mat E = A(Range::all(), Range(1,3)); // using row and column boundaries
对象D E仅仅创建了矩阵头,数据区仍然共用A的数据区。
多个对象如何释放公用的数据区
答案是最后一个被释放的对象释放矩阵数据。opencv使用一种计数机制,当用户复制一次矩阵头信息,计数器加1,当对象矩阵头被释放,计数器减1。当计数器等于0,矩阵数据区将被释放。如果想完全复制数据区,opencv提供了两个函数
clone()和
copyTo()
Mat F = A.clone(); Mat G; A.copyTo(G);
如上代码,对象G F的数据区与A的数据区是独立的。
你应该牢记的
opencv函数返回的数据区 内存分配是自动的使用opencv C++ 接口的时候不需要去理会内存管理
使用赋值和拷贝构造函数,只会创建矩阵头,不会重新创建矩阵数据区
使用Mat的成员函数
clone(),
copyTo()可以复制一份矩阵数据。
数据存储方式
这里的数据存储方式,指的是如何存储pixel value。 比如选择色域,矩阵元素的数据类型。色域标示了用户如何拆分一个给定的颜色。最简单的是灰度图,只需要处理0-255。对于彩色,我们有很多种色域来选择,每种色域都会把彩色信息分解成3或者4个分量,我们可以利用这些分量来新建其他颜色。最流行的当然是RGB色彩空间,主要是因为人眼对色彩的感知机制就是RGB混合方式。3个分量是R,G,B。有时候为了用代码描述透明图片,会引入第4个分量:alpha.
各种色彩空间优势如下:
RGB最接近肉眼的对光谱的感知方式,主动发光设备比如显示器也使用RGB描述颜色。
HSV HLS把颜色分解成色相,饱和度,明度,这种描述方式更接近大脑对颜色的辨识机制。
YCrCb被应用于JPEG格式。
Lab很奇特,如果你需要测量两个给定的颜色有多大差异,使用Lab方式很方便。
每个颜色分量都有各自的取值范围。这样就决定了我们该采用何种数据类型来存储。最小的数据类型是char,8bit。存储的时候可以设定为unsigned char,这样就可以存储0-255(RGB)或者设定为signed char,存储-128–127(LAB中的ab通道)。尽管在3维的色彩空间,已经可以描述1600万色,有时候我们可能会需要更大更精确的控制,这个时候我们需要使用float类型或者double类型来存储各个分量。然而,请记得,增加每个分量的大小,同时就会导致图片占用的空间变大。
显式创建Mat对象
为方便演示,我们使用Mat重载的操作符<<来演示(<<只对二维数组有效)。尽管mat类作为图像容器表现很好,但其本质上仍然是一个数组类。所以我们可以创建一个对象并且操作多维数组。有多种方式去创建mat对象:
Mat构造函数Mat():
Mat M(2,2, CV_8UC3, Scalar(0,0,255)); cout << "M = " << endl << " " << M << endl << endl;
对于2维多通道的图像,首先指定行数(rows),列数(cols),然后指定颜色分量的位深,每个像素有几个通道,opencv预定义了一些宏,规则如下:
CV_[The number of bits per item][Signed or Unsigned][Type Prefix][The channel number] //CV_[分量位深][无符号or有符号][数据类型前缀][通道数量]
opencv预定义的宏最大支持4通道,Scalar是4成员的short类型vector,使用scalar可以初始化所有的矩阵元素为同一个值;如果需要更多类型,使用如上的宏并在末尾的括号内注明通道数量;
2. 使用带数组参数的构造函数:
int sz[3] = {2,2,2}; Mat L(3,sz, CV_8UC(1), Scalar::all(0)); // 矩阵维度,每个维度的容量,数据类型,元素值
这个例子的Mat()构造函数,首先传递矩阵维度,然后是每个维度的容量,接着是数据类型,最后是元素值。
3. 利用已经存在的lpimage指针
IplImage* img = cvLoadImage("greatwave.png", 1); Mat mtx(img); // convert IplImage* -> Mat
4. create()函数
M.create(4,4, CV_8UC(2)); cout << "M = "<< endl << " " << M << endl << endl;
输出:
create()函数不能初始化元素值,只会在矩阵大小和之前不同时重新分配内存。
5. MATLAB风格函数指定元素值以及数据类型
如下:
Mat E = Mat::eye(4, 4, CV_64F); cout << "E = " << endl << " " << E << endl << endl; Mat O = Mat::ones(2, 2, CV_32F); cout << "O = " << endl << " " << O << endl << endl; Mat Z = Mat::zeros(3,3, CV_8UC1); cout << "Z = " << endl << " " << Z << endl << endl;
6. 对于小规模的矩阵,使用逗号分割,直接复制:
Mat C = (Mat_<double>(3,3) << 0, -1, 0, -1, 5, -1, 0, -1, 0); cout << "C = " << endl << " " << C << endl << endl;
7. 创建一个矩阵头然后用clone()和copyTo()复制数据
Mat RowClone = C.row(1).clone(); cout << "RowClone = " << endl << " " << RowClone << endl << endl;
随机赋值
Mat R = Mat(3, 2, CV_8UC3); randu(R, Scalar::all(0), Scalar::all(255));
需要传递给randu()最大值和最小值;
格式化输出
前面的例子使用的都是默认的输出格式,opencv允许你使用不同的风格输出。1. 默认格式:
cout << "R (default) = " << endl << R << endl << endl;
2. python风格:
cout << "R (python) = " << endl << format(R,"python") << endl << endl;
3. CSV风格:
cout << "R (csv) = " << endl << format(R,"csv" ) << endl << endl;
4. numpy风格:
cout << "R (numpy) = " << endl << format(R,"numpy" ) << endl << endl;
5. C
cout << "R (c) = " << endl << format(R,"C" ) << endl << endl;
其他通用结构的输出
2D pointPoint2f P(5, 1); cout << "Point (2D) = " << P << endl << endl;
3D point
Point3f P3f(2, 6, 7); cout << "Point (3D) = " << P3f << endl << endl;
std::vector via cv::Mat
vector<float> v; v.push_back( (float)CV_PI); v.push_back(2); v.push_back(3.01f); cout << "Vector of floats via Mat = " << Mat(v) << endl << endl;
std::vector of points
vector<Point2f> vPoints(20); for (size_t i = 0; i < vPoints.size(); ++i) vPoints[i] = Point2f((float)(i * 5), (float)(i % 7)); cout << "A vector of 2D Points = " << vPoints << endl << endl;
相关文章推荐
- Java程序内存分析:使用mat工具分析内存占用
- CvArr、Mat、CvMat、IplImage、BYTE转换(总结而来) .
- OpenCV使用Mat数据进行K-近邻分类
- OpenCV获取与设置像素点的值的几个方法
- OpenCV中Mat的详解
- Mac中分析hprof文件查找内存泄露
- cv::mat
- Opencv Mat的数据读取
- opencv之Mat类
- 关于在MATLAB读取同一路径下多个txt或mat文件总结
- 使用Memory Analyzer tool(MAT)分析内存泄漏(二)
- 使用Memory Analyzer tool(MAT)分析内存泄漏(一)
- Android内存优化详解以及内存分析工具MAT的使用
- OpenCV实现对某图的裁剪输出
- Mat用法小计
- opencv中矩阵的操作(两种程序)
- 内存分析工具 MAT 的使用
- Shallow heap & Retained heap
- opencv中mat的push_back。
- OpenCV中Mat数据结构