Mat
(1)为其开辟空间
(2)在不需要时立即将空间释放
Mat 是一个类
由两个部分组成:矩阵头(矩阵尺寸,存储方法,存储地址等信息)和一个指向存储所有像素值的矩阵的指针。
同时不要忘了我们正在讨论的是计算量很大的图像处理算法,因此,除非万不得已,我们不应该拷贝 大的图像,因为这会降低程序速度。
每个Mat都有自己的信息头,但共享同一个矩阵。这通过让矩阵指针指向同一地址而实现。
而拷贝构造函数则 只拷贝信息头和矩阵指针 ,而不拷贝矩阵。
1 Mat A, C; // 只创建信息头部分2 A = imread(argv[1], CV_LOAD_IMAGE_COLOR); // 这里为矩阵开辟内存3 4 Mat B(A); // 使用拷贝构造函数5 6 C = A; // 赋值运算符
以上代码中的所有Mat对象最终都指向同一个也是唯一一个数据矩阵。
虽然它们的信息头不同,但通过任何一个对象所做的改变也会影响其它对象
1 Mat D (A, Rect(10, 10, 100, 100) ); // using a rectangle2 Mat E = A(Range:all(), Range(1,3)); // using row and column boundaries
现在你也许会问,如果矩阵属于多个 Mat 对象,那么当不再需要它时谁来负责清理?简单的回答是:最后一个使用它的对象。通过引用计数机制来实现。无论什么时候有人拷贝了一个 Mat 对象的信息头,都会增加矩阵的引用次数;反之当一个头被释放之后,这个计数被减一;当计数值为零,矩阵会被清理。
但某些时候你仍会想拷贝矩阵本身(不只是信息头和矩阵指针),这时可以使用函数 或者 。
1 Mat F = A.clone();2 Mat G;3 A.copyTo(G);
现在改变 F 或者 G 就不会影响 Mat 信息头所指向的矩阵。
总结一下,你需要记住的是
- OpenCV函数中输出图像的内存分配是自动完成的(如果不特别指定的话)。
- 使用OpenCV的C++接口时不需要考虑内存释放问题。
- 赋值运算符和拷贝构造函数( ctor )只拷贝信息头。
- 使用函数 或者 来拷贝一副图像的矩阵。
常用的构造函数有:
Mat::Mat() 无参数构造方法; Mat::Mat(int rows, int cols, int type) 创建行数为 rows,列数为 col,类型为 type 的图像; Mat::Mat(Size size, int type) 创建大小为 size,类型为 type 的图像; Mat::Mat(int rows, int cols, int type, const Scalar& s)创建行数为 rows,列数为 col,类型为 type 的图像,并将所有元素初始 化为值 s; Mat::Mat(Size size, int type, const Scalar& s) 创建大小为 size,类型为 type 的图像,并将所有元素初始化为值 s; Mat::Mat(const Mat& m) 将 m 赋值给新创建的对象,此处不会对图像数据进行复制,m和新对象共用图像数据; Mat::Mat(int rows, int cols, int type, void* data, size_t step=AUTO_STEP) 创建行数为 rows,列数为 col,类型为 type 的图像,此构造函数不创建 图像数据所需内存,而是直接使用 data 所指内存,图像的行步长由 step 指定。 Mat::Mat(Size size, int type, void* data, size_t step=AUTO_STEP) 创建大小为 size,类型为 type 的图像,此构造函数不创建图像数据所需内存,而是直接使用 data 所指内存,图像的行步长由 step 指定。 Mat::Mat(const Mat& m, const Range& rowRange, const Range& colRange) 创建的新图像为 m 的一部分,具体的范围由 rowRange 和 colRange 指定,此构造函数也不进行图像数据的复制操作,新图像与 m 共用图像数据; Mat::Mat(const Mat& m, const Rect& roi) 创建的新图像为m的一部分,具体的范围 roi 指定,此构造函数也不进行图像数据的复制操作,新图像与m 共用图像数据。这些构造函数中, 很多都涉及到类型 type。 type 可以是 CV_8UC1, CV_16SC1, …,CV_64FC4 等。里面的 8U 表示 8 位无符号整数, 16S 表示 16 位有符号整数, 64F 表示 64 位浮点数(即 double 类型); C 后面的数表示通道数,例如 C1 表示一个 通道的图像, C4 表示 4 个通道的图像,以此类推。
CvScalar定义可存放1—4个数值的数值,其结构体如下:
typedef struct CvScalar
{ double val[4];}CvScalar;例如:CvScalar s;
如果使用的图像是1通道的,则s.val[0]中存储数据
如果使用的图像是3通道的,则s.val[0],s.val[1],s.val[2]中存储数据
Mat 不但是一个很赞的图像容器类,它同时也是一个通用的矩阵类,所以可以用来创建和操作多维矩阵。创建一个Mat对象有多种方法:
1 Mat M(2,2, CV_8UC3, Scalar(0,0,255)); 2 cout << "M = " << endl << " " << M << endl << endl;
1 int sz[3] = {2,2,2}; 2 Mat L(3,sz, CV_8UC(1), Scalar::all(0));
Mat的作用
The class Mat represents an n-dimensional dense numerical single-channel or multi-channel array. It can be used to store real or complex-valued vectors and matrices, grayscale or color images, voxel volumes, vector fields, point clouds, tensors, histograms (though, very high-dimensional histograms may be better stored in a SparseMat ).
上面的一段话引用自官方的文档,Mat类用于表示一个多维的单通道或者多通道的稠密数组。能够用来保存实数或复数的向量、矩阵,灰度或彩色图像,立体元素,点云,张量以及直方图(高维的直方图使用SparseMat保存比较好)。简而言之,Mat就是用来保存多维的矩阵的。
Mat的常见属性
- data uchar型的指针。Mat类分为了两个部分:矩阵头和指向矩阵数据部分的指针,data就是指向矩阵数据的指针。
- dims 矩阵的维度,例如5*6矩阵是二维矩阵,则dims=2,三维矩阵dims=3.
- rows 矩阵的行数
- cols 矩阵的列数
- size 矩阵的大小,size(cols,rows),如果矩阵的维数大于2,则是size(-1,-1)
- channels 矩阵元素拥有的通道数,例如常见的彩色图像,每一个像素由RGB三部分组成,则channels = 3
- type 表示了矩阵中元素的类型以及矩阵的通道个数,它是一系列的预定义的常量,其命名规则为CV_(位数)+(数据类型)+(通道数)。具体的有以下值:
CV_8UC1 CV_8UC2 CV_8UC3 CV_8UC4 CV_8SC1 CV_8SC2 CV_8SC3 CV_8SC4 CV_16UC1 CV_16UC2 CV_16UC3 CV_16UC4 CV_16SC1 CV_16SC2 CV_16SC3 CV_16SC4 CV_32SC1 CV_32SC2 CV_32SC3 CV_32SC4 CV_32FC1 CV_32FC2 CV_32FC3 CV_32FC4 CV_64FC1 CV_64FC2 CV_64FC3 CV_64FC4 - depth 矩阵中元素的一个通道的数据类型,这个值和type是相关的。例如 type为 CV_16SC2,一个2通道的16位的有符号整数。那么,depth则是CV_16S。depth也是一系列的预定义值, 将type的预定义值去掉通道信息就是depth值: CV_8U CV_8S CV_16U CV_16S CV_32S CV_32F CV_64F
- elemSize 矩阵一个元素占用的字节数,例如:type是CV_16SC3,那么elemSize = 3 * 16 / 8 = 6 bytes
- elemSize1 矩阵元素一个通道占用的字节数,例如:type是CV_16CS3,那么elemSize1 = 16 / 8 = 2 bytes = elemSize / channels
通过相关返回值的On-the-fly地址计算
该函数输入为数据类型及需求元素的坐标,返回的是一个对应的值。如果用 get ,则是constant,如果是用 set ,则为non-constant. 处于程序安全,当且仅当在 debug 模式下 它会检查你的输入坐标是否有效或者超出范围. 如果坐标有误,则会输出一个标准的错误信息. 和高性能法(the efficient way)相比, 在 release模式下,它们之间的区别仅仅是On-the-fly方法对于图像矩阵的每个元素,都会获取一个新的行指针,通过该指针和[]操作来获取列元素.
当你对一张图片进行多次查询操作时,为避免反复输入数据类型和at带来的麻烦和浪费的时间,OpenCV 提供了:basicstructures:Mat_ <id3> data type. 它同样可以被用于获知矩阵的数据类型,你可以简单利用()操作返回值来快速获取查询结果. 值得注意的是你可以利用 函数来用同样速度完成相同操作. 它仅仅是为了让懒惰的程序员少写点 >_<