1. Mat是Opencv转向C++后设计的图像类,替代原来的IpIImage和cvMat。
2. Mat类由两个数据部分组成:
(1)矩阵信息头(包含矩阵尺寸,储存方法,储存地址等信息)
(2)指向储存所有像素值的矩阵(根据所选储存方法不同,矩阵的维数不同)。
3. Mat的内存是自动分配和释放的。
4. 为了减小在函数中传递图像的开销,Mat使用引用计数机制,每个Mat对象拥有自己的信息头,但是共享一个矩阵。拷贝构造函数只拷贝信息头和矩阵空间的指针。如果想完全拷贝矩阵,需要使用 clone()或者cpoyto()函数。可以创建只引用部分数据的信息头,来创建一个感兴趣的区域。
5. Mat重载了 << 操作符,并且支持格式化输出。
例如:
Mat R = Mat(3, 2, CV_8UC3);
//默认方式
cout << R << endl << endl;
//Python
cout << format(R,"python") << endl << endl;
//C语言
cout << format(R,"C" ) << endl << endl;</span>
Opencv同样支持使用 << 操作符打印其他常用数据结构,比如:
//2维点
Point2f P(5, 1);
cout << "Point (2D) = " << P << endl << endl;
//3维点
Point3f P3f(2, 6, 7);
cout << "Point (3D) = " << P3f << endl << endl;
//基于cv::Mat的std::vector
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点
vector<Point2f> vPoints(20);
for (size_t E = 0; E < vPoints.size(); ++E)
vPoints[E] = Point2f((float)(E * 5), (float)(E % 7));
cout << "A vector of 2D Points = " << vPoints << endl << endl;
6. 除了在构造函数中可以创建图像,也可以使用 Mat 类的 create()函数创建图像。如果 create()函数指定的参数与图像之前的参数相同,则不进行实质的内存申请操作;如果参数不同,则减少原始数据内存的索引,并重新申请内存。
7. Mat储存像素值需要指定:
(1) 颜色空间。指的是对一个给定的颜色,如何组合颜色元素以对其编码。
最简单的颜色空间要属灰度级空间,只处理黑色和白色,对它们进行组合可以产生不同程度的灰色。
对于彩色方式则有更多种类的颜色空间,但不论哪种方式都是把颜色分成三个或者四个基元素,通过组合基元素可以产生所有的颜色。有很多的颜色系统,各有自身优势:
①RGB是最常见的,这是因为人眼采用相似的工作机制,它也被显示设备所采用。Opencv默认的颜色顺序为BGR。
②HSV和HLS把颜色分解成色调、饱和度和亮度/明度。这是描述颜色更自然的方式,比如可以通过抛弃最后一个元素,使算法对输入图像的光照条件不敏感。
③YCrCb在JPEG图像格式中广泛使用。
④CIE L*a*b*是一种在感知上均匀的颜色空间,它适合用来度量两个颜色之间的 距离 。
(2) 数据类型。每个组成元素都有其自己的定义域,取决于其数据类型。
如何存储一个元素决定了我们在其定义域上能够控制的精度。最小的数据类型是 char ,占一个字节或者8位,可以是有符号型(0到255之间)或无符号型(-127到+127之间)。尽管使用三个 char 型元素已经可以表示1600万种可能的颜色(使用RGB颜色空间),但若使用float(4字节,32位)或double(8字节,64位)则能给出更加精细的颜色分辨能力。但同时也要切记增加元素的尺寸也会增加了图像所占的内存空间
8. 常用的构造函数有:
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 个通道的图像,以此类推。
如果你需要更多的通道数,需要用宏 CV_8UC(n)。
例如:Mat M(3,2, CV_8UC(5));//创建行数为 3,列数为 2,通道数为 5 的图像
9. 对于单通道图像,其元素类型一般为 8U(即 8 位无符号整数) ,当然也可以是 16S、32F 等;这些类型可以直接用 uchar、short、float 等 C/C++语言中的基本数据类型表达。
如果多通道图像,如 RGB 彩色图像,需要用三个通道来表示。在这种情况下, 如果依然将图像视作一个二维矩阵, 那么矩阵的元素不再是基本的数据类型。
OpenCV 中有模板类 Vec,可以表示一个向量。OpenCV 中使用 Vec 类预定义了一些小向量,可以将之用于矩阵元素的表达。
typedef Vec<uchar, 2> Vec2b;
typedef Vec<uchar, 3> Vec3b;
typedef Vec<uchar, 4> Vec4b;
typedef Vec<short, 2> Vec2s;
typedef Vec<short, 3> Vec3s;
typedef Vec<short, 4> Vec4s;
typedef Vec<int, 2> Vec2i;
typedef Vec<int, 3> Vec3i;
typedef Vec<int, 4> Vec4i;
typedef Vec<float, 2> Vec2f;
typedef Vec<float, 3> Vec3f;
typedef Vec<float, 4> Vec4f;
typedef Vec<float, 6> Vec6f;
typedef Vec<double, 2> Vec2d;
typedef Vec<double, 3> Vec3d;
typedef Vec<double, 4> Vec4d;
typedef Vec<double, 6> Vec6d;
例如 8U 类型的 RGB 彩色图像可以使用 Vec3b,3 通道 float 类型的矩阵可以使用 Vec3f。
对于 Vec 对象,可以使用[]符号如操作数组般读写其元素,如:
Vec3b color; //用 color 变量描述一种 RGB 颜色
color[0]=255; //B 分量
color[1]=0; //G 分量
color[2]=0; //R 分量