Mat
Mat是一个基本的类,它包含两部分的数据:一个是矩阵头,另一个就是一个指向矩阵的指针;对于矩阵头它包含这些信息:矩阵的大小,用来存储的方法以及矩阵存储的地址等,而矩阵中包含着一些像素值(这些像素值的维度取决于我们选择储存的方式)。矩阵头的大小是一个常量,然而矩阵自己的大小却一般不相同,取决于储存的图片。
我们在进行图像处理时,需要我们尽可能地减少对哪些很大的图像的一些不必要的复制,为了解决这个问题,OpenCV使用了一个参考计数机制。这个系统的原理是:每个Mat对象都有自己的矩阵头,然而矩阵本身却可以在不对象之间共享,只要让他们的矩阵指针指向相同的地址就可以了。这就和C++中类的思想一致了。
而且,对象之间的相互赋值也只复制矩阵的矩阵头和指针,而不是图像数据本身:
Mat A,C; //创建矩阵头(就好像C++中的对象),不过没有所谓的构造//函数来分配内存,因此这时候是没有实际的数据的
A=imread(argv[1],CV_LOAD_IMAGE_COLOR);//分配内存
C=A;//赋值运算符,只是复制header,数据本身不会复制
上面所有的对象最后都指向同一个数据矩阵,然而,他们的矩阵头是不一样的,一旦改变他们中任意一个的数据都会影响其他的Mat.实际上,不同的对象只是提供不同的方法来处理同一块数据。
更有趣的是我们可以创建矩阵头使它仅仅指向整块数据的一个子区域。例如:可以用一个新的边界创建一个矩阵头以此来创建一个新的ROI:
MatD(A,Rect(10,10,100,100));//使用一个举行区域来创建
Mat E=A(Range::all(),Range(1,3));//使用行和列边界来创建
如果一块矩阵数据属于多个Mat对象,那么谁来负责清理它呢?答案是:最后使用这块数据的那个Mat对象负责清理。这就是前面提到的参考计数机制,任何Mat对象复制矩阵头,都会有一个计数器增加,一旦某个Mat对象清理了自己的矩阵头,那么计数器就会减少,直到最后那个清理的Mat对象清理完成,这个时候计数器恰好减少到0,这时候数据块就会被释放。
拷贝矩阵本身,OpenCV提供了clone()和copyTo()函数,这个时候是复制数据块,每个Mat对象都将有自己的数据块,相互之间不受影响,相互独立:
Mat F=A.clone();
Mat G;
A. copyTo(G);
总结:
Ø 赋值运算符和复制构造函数都只拷贝矩阵头,而拷贝数据
Ø 拷贝数据用clone()和copyTo()函数
Storing methods
主要是介绍怎么保存像素值。你可以选择颜色空间和其使用的数据类型。颜色空间指的是我们怎么组合基色来对给定的颜色进行编码。最简单的一个例子就是灰度,在灰度中我们对颜色的处理就是黑与白,这二者的不同组合使我们能创造出各种灰度背景。
目前最好的颜色空间是RGB,因为我们的眼睛也是这种颜色空间。它的基色是红、绿和蓝。有时候为了对一种颜色的透明度进行编码,还引进了第四种元素,就是alpha(A)。
目前有几种比较常用的颜色空间:
Ø RGB是最常用的,因为和我们眼睛的原理类似(OpenCV就是采用的RGB)
Ø HSV和HLS将颜色分解成色调、饱和度和亮度等基本元素,这是我们描述颜色的一种更自然的方式。
Ø YCrCb被更广泛地应用于JPEG图像格式中
Ø CIE L*a*b* 是一种感知颜色空间,当你需要去测量从一种颜色到另一种颜色的距离的时候会很方便
每种颜色基元都有自己的值域。最小的数据类型是char:即一个字节(或8位),对于无符号的就是0—255,对于有符号的就是-127-+127,在这种情况下,RGB三种颜色基元就可以组成一千六百万中颜色。我们也可以使用浮点数等形式来获取更多的颜色表示,但不要忘了,增加颜色基元的大小同样也会让图像在内存中所占的空间不断增大。
创建一个Mat对象
可以使用<<操作符输出Mat的值,但是这种情况仅对二维矩阵适用。
尽管Mat作为一个图像数据容器效果很好,但它还是一个通用的矩阵类,因此,我们可以创建和操作多维矩阵。可以用多种方式来创建Mat对象:
Ø Mat()构造函数:
Mat M(2,2,CV_8UC3,Scalar(0,0,225));
Cout<<”M=”<<endl<<””<<endl<<endl;
对于二维多通道图像首先需要定义它的大小:行和列的大小。
然后我们需要确定我们使用什么数据类型来存储以及每一个矩阵中的点有几个通道数,为了定义这两个,有:
CV_[The number of bits peritem][Signed or Unsigned][Type Prefix]C[The channel number]
CV_8UC3表示我们使用无符号char型来储存数据,每个像素值有3个这样的char型来表示,即3X8位=24位来表示一个像素。Scalar是一个有4个元素的小容器。
Ø 使用C/C++数组并通过构造函数初始化
intsz[3] = { 2, 2, 2 };
MatL(3, sz, CV_8UC(1), Scalar::all(0));
上述例子创建了一个超过二维的矩阵。首先告诉创建一个3维的矩阵,然后传递一个指针包含每一维的大小,其他保持一样。
Ø 通过一个已有的IplImage指针创建
IplImage* img =cvLoadImage("F:/Photo/OpenCV_Photo/1.jpg",1);
Mat mtx(img);
Ø 通过Create()函数(不能用这个函数来初始化矩阵,只能用来重新分配矩阵数据内存用,当新的矩阵尺寸和旧的不匹配时用)
M.create(4, 4, CV_8UC(2));
cout<< "M= " << endl << " " << M << endl;
Ø Matlab格式的初始化:zero(),ones(),eye()
Mat E =Mat::eye(4, 4, CV_64F);
cout << "E= " <<endl << " " << E<< endl;
Mat O = Mat::ones(2, 2, CV_32F);
cout << "O= " <<endl << " " << O<< endl;
Mat Z = Mat::zeros(3, 3, CV_8UC1);
cout<< "Z= " << endl << " " << Z << endl;
Ø 对于小的矩阵可以使用直接初始化
Mat C =(Mat_<char>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
cout<< "C= " << endl << " " << C << endl;
Ø 可以使用clone()或者copyTo()根据现有的Mat对象来创建
MatRowClone = C.row(1).clone();
Ø 可以使用randu()函数来随机创建一个矩阵,给定矩阵的最大和最小取值:
Mat R =Mat(3, 2, CV_8UC3);
randu(R,Scalar::all(0), Scalar::all(255));
Scalar::all(n),是将所有元素都设置为n。这里是三通道,所以,此处的Scalar::all(0)相当于Scalar(0,0,0).
数据的输出
其他OpenCV数据结构都可以通过<<操作符来输出:
Ø 2D Point
Point2f P(5,1);
Cout<<P<<endl;
Ø 3D Point
Point3f p(2,6,7);
Cout<<p<<endl;
Ø 点的vector容器
Vector<Point2f> vPoints(20);
For(size_ti=0;i<vPoints.size();++i)
vPoints[i]=Point2f((float)(i*5),(float)(i%7));
学习代码如下:
/************************************************** *** OpenCV学习笔记一(Mat) *********** *** Date:2016/02/26 *********** *** author:York *********** **************************************************/ #include<cv.h> #include<highgui.h> using namespace cv; using namespace std; int main() { /* 第一种创建Mat对象的方式 */ Mat M(2, 2, CV_8UC3, Scalar(0, 0, 255)); cout << "M= " << endl << " " << M << endl; /// /* 第二种创建Mat对象的方式 */ int sz[3] = { 2, 2, 2 }; Mat L(3, sz, CV_8UC(1), Scalar::all(0)); //cout << "L= " << endl << " " << L << endl; /// /* 第三种创建Mat对象的方式 */ IplImage* img = cvLoadImage("F:/Photo/OpenCV_Photo/1.jpg",1); Mat mtx(img); //cout << "mtx= " << endl << " " << mtx << endl; /// /* 第四种创建Mat对象的方式 */ M.create(4, 4, CV_8UC(2)); cout << "M= " << endl << " " << M << endl; /// /* 第五种创建Mat对象的方式 */ Mat E = Mat::eye(4, 4, CV_64F); cout << "E= " << endl << " " << E << endl; Mat O = Mat::ones(2, 2, CV_32F); cout << "O= " << endl << " " << O << endl; Mat Z = Mat::zeros(3, 3, CV_8UC1); cout << "Z= " << endl << " " << Z << endl; /// /* 第六种创建Mat对象的方式 */ Mat C = (Mat_<char>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0); cout << "C= " << endl << " " << C << endl; /// /* 第七种创建Mat对象的方式 */ Mat RowClone = C.row(1).clone(); cout << "RowClone = " << endl << " " << RowClone << endl; /// /* 第八种创建Mat对象的方式 */ Mat R = Mat(3, 2, CV_8UC3); randu(R, Scalar::all(0), Scalar::all(255)); cout << "R = " << endl << " " << R << endl; system("pause"); return 0; }