一、初识Mat类
Mat是OpenCV最基本的数据结构,Mat即矩阵(Matrix)的缩写,Mat数据结构主要包含2部分:Header和Pointer。Header中主要包含矩阵的大小,存储方式,存储地址等信息;Pointer中存储指向像素值的指针。我们在读取图片的时候就是将图片定义为Mat类型,其重载的构造函数一大堆,
而矩阵又是图像的基本数据结构,我们做的所有动作几乎都是在矩阵的基础之上完成的。比如Mat img;有时,我们又需要详细地定义出矩阵的维度以及长、宽、数据类型等信息:Matimg(width,height,CV_8U);这就直接导致了Mat类一个庞大的构造函数群,如下所示:
Mat::Mat()
Mat::Mat(int rows, int cols, int type)
Mat::Mat(Size size, int type)
.....
Mat::Mat(int ndims, const int* sizes, inttype, void* data, const size_t* steps=0)
Mat::Mat(const Mat& m, const Range*ranges)
二、深入结构
进一步数据,图像基本结构是二维的,3D图像还会是三维的,彩色图像还有多个channel(通道),而数据在内存中是一维存储的,;为了便于编程使用,opencv对一维数据进行矩阵的抽象封装,这个就是Mat类;Mat是一个基础类,封装了构造函数,重载运算符和基础的运算函数(很多类似于matlab的函数)。比如存一张10*10像素的单通道float图像,图像数据总共10*10*4*1字节,data指向第一个字节;Mat本身还有一个成员 int type;这个就是来记录Mat的数据类型;什么CV_32F等
现在看看具体mat矩阵类中怎么用信息头和矩阵?
用法一、赋值运算符和拷贝构造函数( ctor )只拷贝信息头,让每个 Mat 对象有自己的信息头,但共享同一个矩阵。
Mat A, C; // 只创建信息头部分
A = imread(argv[1], CV_LOAD_IMAGE_COLOR);// 这里为矩阵开辟内存
Mat B(A); // 使用拷贝构造函数
C = A; // 赋值运算符
Mat D (A, Rect(10, 10, 100, 100) ); //using a rectangle
Mat E = A(Range:all(), Range(1,3)); //using row and column boundaries
用法二、使用函数 clone() 或者copyTo() 来拷贝一副图像的矩阵,拷贝矩阵本身(不只是信息头和矩阵指针)
Mat F = A.clone();
Mat G;
A. copyTo(G);
三、mat类的七种方法略
下面会给出链接,想看的可以点击链接
http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/core/mat%20-%20the%20basic%20image%20container/mat%20-%20the%20basic%20image%20container.html
1) 使用Mat()构造函数
2) 在c/c++中通过构造函数进行初始化
3) 用已经存在的IplImage指针创建信息头
4) 利用Create()函数
5) 采用matlab式的初始化方式
6) 对小矩阵使用逗号分隔式初始化函数
7) 用已存在的对象创建新信息头clone()或copyTo()
注意:流操作符<<对于Mat的操作,仅限于Mat是2维的情况
唯一要说的感觉是 CV_(S|U|F)C<通道数>,例如,数据类型可能是CV32FC1,即32bit的浮点数,或CV_8UC3,8bit的无符号整数,或CV_8UC3,无符号8bit整数,3通道,等等
Mat_<uchar>对应的是CV_8U,
Mat_<char>对应的是CV_8S,
Mat_<int>对应的是CV_32S,
Mat_<float>对应的是CV_32F,
Mat_<double>对应的是CV_64F
CV_8UC3 意味着我们使用那些长的8 位无符号的 char 类型和每个像素都有三个项目的这三个通道的形成。这是预定义的四个通道数字。Scalar 是四个元素短向量。
还有就是CV_32F和CV_32F
看CV_32FC1和CV_64FC1的名字就知道,前者是32位数据,后者是64位数据。因此前者类型的数据必须以指向32位数据类型的指针存取,否则会报错,而后者类型的数据必须以指向64位数据类型的指针存取,否则会报错。
也就是说,你如果用cv_32fc1,那么后面对该矩阵的输入输出的数据指针类型都应该是float,这在32位编译器上是32位浮点数,也就是单精度。
你如果用cv_64fc1,那么后面对该矩阵的输入输出的数据指针类型都应该是double,这在32位编译器上是64位浮点数,也就是双精度。
看一个代码,略微感受一下Mat
typedef struct CVMat
{
int type;
int step;
int* refcount;
int hdr_refcount;
union
{
uchar* ptr;
short* s;
int* i;
float* fl;
double* db;
}data;
#ifdef __cplusplus
union
{
int rows;
int height;
};
union
{
int cols;
int width;
};
#else
int rows;
int cols;
#endif
}
CvMat;
Scalar的解释
Mat M(7,7,CV_32FC2,Scalar(1,3));
解释如下:创建一个M矩阵,7行7列,类型为CV_32F,C2表示有2个通道。Scalar(1,3)是对矩阵进行初始化赋值。第一个通道全为1,第2个通道全为3,如果是CV_32FC3第一个通道全为1,第2个通道全为3,第三通道是0,如果是CV_32FC1,只显示第一通道为1
Mat L(3,sz, CV_8UC(1), Scalar::all(0));
初始化全部为0