部分参考: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并初始化赋零
Mat定义: 早期opencv为了在内存(memory)中存放图像采用IplImage 的C语言结构体,不足在于手动内存管理,其依据是用户要为开辟和销毁内存负责。C++中类的概念,自动的内存管理(不严谨地说)。OpenCV在2.0版本中引入了一个新的C++接口Mat。C++接口唯一的不足是当前许多嵌入式开发系统只支持C语言。
关于Mat ,不必再手动地(1)为其开辟空间(2)在不需要时立即将空间释放。但手动地做还是可以的:大多数OpenCV函数仍会手动地为输出数据开辟空间。当传递一个已经存在的 Mat 对象时,开辟好的矩阵空间会被重用。也就是说,我们每次都使用大小正好的内存来完成任务。使用OpenCV的C++接口时不需要考虑内存释放问题。
Tips:妈妈再也不用担心我搞不懂struct和class的区别了。
C里面的结构(struct)只是把各种不同的数据类型结合在一起,变成一种自定义的数据类型。结构是完全开放的,任意一个函数,只要能访问到这个结构,就可以随意操纵其中的数据。C语言struct不是类,没有成员函数、构造函数和析构函数的概念,也没有private和public、static的概念。对于一个结构体必须有专门函数去释放它。
类(class)除了是将不同的数据类型以私有的形式(private)组合在一起之外,还提供了访问这些数据的方法(即类函数)。用户只能用类提供的接口(类函数)来访问并操纵类中的数据,就使类具备了封装的功能,有效地保护了数据。同时,类还有构造和析构、继承和多态等多种优点。
C++中将结构struct当成类来处理,所以C++的struct可以包含C++类的所有东西,例如构造函数,析构函数,友元等。C++ struct里面成员初始化的形式和类是相同的,不可以直接初始化,就是不可以定义成员的时候同时初始化。C语言 struct中间的某个类型(例如int)也不可以直接初始化。
C和C++struct区别:1)类型不同
1 2 3 4 5 6 |
struct HE{ int a; }; struct HE a; //C语言 变量方式 HE a; //C++语言 |
2)typedef struct 在C++和C语言中都是一样的功能,定义别名。
1 2 3 4 5 6 7 8 |
#include <stdio.h>; #include <stdlib.h>; typedef struct HE { int a; } *PHE,DHE,EHE; //这是定义了一个struct HE*类型别名和两个普通别名,main函数只考虑指针型别名。 PHE a = (PHE)malloc(sizeof(struct HE)); //这是C语言的写法 |
1 2 3 4 5 6 7 |
#include <stdio.h>; #include <stdlib.h>; typedef struct HE{ int a; } *PHE,DHE,EHE; //这里定义了一个指针型变量和两个普通变量 PHE a = new HE(); //这是C++语言的写法 |
回归正题:
Mat 是一个类,由两个数据部分组成:矩阵头(包含矩阵尺寸,存储方法,存储地址等信息)和一个指向存储所有像素值的矩阵(根据所选存储方法的不同矩阵可以是不同的维数)的指针。矩阵头的尺寸是常数值,但矩阵本身的尺寸会依图像的不同而不同,通常比矩阵头的尺寸大数个数量级。因此,当在程序中传递图像并创建拷贝时,大的开销是由矩阵造成的,而不是信息头。
OpenCV使用引用计数机制。其思路是让每个 Mat 对象有自己的信息头,但共享同一个矩阵。这通过让矩阵指针指向同一地址而实现。而拷贝构造函数则 只拷贝信息头和矩阵指针 ,而不拷贝矩阵。
1 2 3 4 |
cv::Mat A, C; // 只创建信息头部分 A = imread(argv[1], CV_LOAD_IMAGE_COLOR); // 这里为矩阵开辟内存 cv::Mat B(A); // 使用拷贝构造函数 C = A; // 赋值运算符 |
所有Mat对象最终都指向同一个也是唯一一个数据矩阵。虽然它们的信息头不同,但通过任何一个对象所做的改变也会影响其它对象。
如果矩阵属于多个 Mat 对象,那么当不再需要它时谁来负责清理?简单的回答是:最后一个使用它的对象。通过引用计数机制来实现。无论什么时候有人拷贝了一个 Mat 对象的信息头,都会增加矩阵的引用次数;反之当一个头被释放之后,这个计数被减一;当计数值为零,矩阵会被清理。
函数 clone() 或者 copyTo() :拷贝矩阵本身(不只是信息头和矩阵指针)
1 2 3 |
Mat F = A.clone(); Mat G; A.copyTo(G); |
显式地创建一个 Mat 对象
1)Mat() 构造函数
1 2 3 |
//<em>CV_8UC3</em> 表示使用8位的 unsigned char 型,每个像素由三个元素组成三通道 Mat M(2,2, CV_8UC3, Scalar(0,0,255)); //创建3三通道,初始值为0,0,255 Mat MM(fsrc.cols,fsrc.rows, CV_8UC(1), Scalar::all(0)); //单通道,初始值赋零 |
2)create() 函数
1 2 |
M.create(4,4, CV_8UC(2));//不能初始化赋值 cout << "M = "<< endl << " " << M << endl << endl; |
其他以后再介绍吧!