关于MAT
在对图像进行处理时,首先需要将图像载入到内存中,而Mat就是图像在内存中的容器,管理着图像在内存中的数据。Mat是C++ 的一个类,由于OpenCV2中引入了内存自动管理机制,所以不必手动的为Mat开辟内存空间以及手动的释放内存。Mat中包含的数据主要由两个部分构成:
1.矩阵头(矩阵尺寸、存储方法、存储地址等信息)(大小固定)2.一个指向存储图像所有像素值的矩阵(根据所选的存储方法不同的矩阵可以是不同的维数)的指针。
在图像处理中,对图像的处理不可能是在一个函数中完成的,这就需要在不同的函数间传递Mat。同时,图像处理的计算量是很大,除非万不得已就不要去传递比较大的Mat。这就要求使用某种机制来实现Mat的快速传递。Mat中主要有矩阵头和一个指向矩阵的指针,矩阵头是一个常数值,但是矩阵保存了图像所有的像素值,通常会比矩阵头大几个数量级,因此传递Mat是主要的消耗是在矩阵复制上。
为了解决这个问题,OpenCV中引入了计数机制。每个Mat都有自己的信息头,但是共享同一个矩阵,也就是在传递Mat时,只复制矩阵头和指向矩阵的指针。
1: Mat a,c ;
2: a = imread("d:\\test.jpg",1) ;3: Mat b(a) ; //拷贝构造函数4: a = c ; //复制运算符
多个对象同时使用一个矩阵,那么当不需要该矩阵时, 谁来负责清理 ?上面代码中3个Mat对象a,b,c指向同一个矩阵,由于都指向了同一个矩阵,某一个对象对矩阵进行操作时也会影响到其他对象读取到的矩阵。
简单的回答是,最后一个使用它的对象。
通过引用计数机制,无论什么时候Mat对象的信息头被复制了,都会增加矩阵的引用次数加1;
反之,当一个Mat的信息头被释放后,引用计数就会被减1;当计数被减到0时,矩阵就会被释放。
有些时候还是需要拷贝矩阵本身的,这时候可以使用clone和 copyTo。
通过clone和copyTo创建的Mat,都有自己的矩阵,修改其中一个的矩阵不会对其他的造成影响。
mat的数据存储
Mat_<uchar>对应的是CV_8U,Mat_<char>对应的是CV_8S,Mat_<int>对应的是CV_32S,Mat_<uint>对应的是CV_32U,Mat_<float>对应的是CV_32F,Mat_<double>对应的是CV_64F
这里还需要注意一个问题,很多OpenCV的函数支持的数据深度只有8位和32位的,
所以要少使用CV_64F,但是vs的编译器又会把float数据自动变成double型,有些不太爽。
还有个需要注意的问题,就是流操作符<<对于Mat的操作,仅限于Mat是2维的情况。
Mat的存储是逐行的存储的。
Mat的创建
方式有两种:
1.Mat(行,列,类型(值))
2. 调用create(行,列,类型)
// make a 7x7 complex matrix filled with 1+3j.
1. Mat M(7,7,CV_32FC2,Scalar(1,3));
// and now turn M to a 100x60 15-channel 8-bit matrix.
2. M.create(100,60,CV_8UC(15)); // C代表channel通道数
要是想创建更高维的矩阵,要写成下面的方式:int sz[] = {100, 100, 100};Mat bigCube(3, sz, CV_8U, Scalar::all(0));