Mat是一个类,有两个数据部分组成:矩阵头(包含矩阵尺寸、存储方法、存储地址等信息)和一个指向存储所有像素值的矩阵(根据所选存储方法的不同,矩阵可以是不同的维数)的指针。矩阵头的尺寸是一个常数值,但矩阵本身尺寸会依图像的不同而不同,通常比矩阵头的尺寸大数个数量级。因此当程序中传递图像并创建副本时,大的开销是由矩阵造成的,而不是信息头。为了解决这个问题,OpenCV使用了引用计数机制。其思路是让每个Mat对象有自己的信息头,但共享一个矩阵。这通过让矩阵指针指向同一地址而实现。而拷贝函数则只复制信息头和矩阵指针,而不是复制矩阵。
Mat A,C;//仅创建信息头部分
A = imread("1.jpg",CV_LOAD_IMAGE_COLOR);//这里矩阵开辟内存
Mat B(A);//使用拷贝构造函数
C=A;//赋值运算符
以上代码的所有Mat对象最终都指向同一个也是唯一 一个数据矩阵。虽然它们的信息头不同,但通过任何一个对象所做的改变也会影响其他对象。实际上,不同的对象只是访问相同数据的不同途径而已。这里还要提及一个比较帮的功能:我们可以创建只引用部分数据的信息头。比如想要创建一感兴趣区域(ROI),只需要创建包含边界信息的信息头:
Mat D(A,Rect(10,10,100,100));//使用矩形界定
Mat E=A(Range:all(),Range(1,3));//用行和列界定
如果矩阵属于多个Mat对象,那么当不再需要它时,最后一个使用它的对象,通过英勇计数机制来清理。我们无论什么时候复制一个Mat对象的信息头,都会增加矩阵的引用次数。反之,当一个头被释放之后,这个计数被减一;当计数值为0时,这个矩阵会被清理。但某些时候仍像复制矩阵本身(不只是信息头和矩阵指针),这时可以使用函数clone()或者copy To()。
Mat F=A.clone();
Mat G;
A.copyTo(G);
现在改变F或G就不会影响Mat信息头所指向的矩阵。OpenCV函数中输出图像的内存分配是自动完成的(如果不是特别指定),使用OpenCV的C++接口时不需要考虑内存释放问题,赋值运算符和拷贝构造函数只复制信息头,使用函数clone()或者copyTo()来复制一幅图像的矩阵。下面给出用Mat()输出数据。
#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
using namespace std;
using namespace cv;
//--------------------------------------【main( )函数】-----------------------------------------
// 描述:控制台应用程序的入口函数,我们的程序从这里开始执行
//-----------------------------------------------------------------------------------------------
int main(int,char**)
{
//改变控制台的前景色和背景色
system("color 8F");
Mat I = Mat::eye(4, 4, CV_64F);
I.at<double>(1,1) = CV_PI;
cout << "\nI = " << I << ";\n" << endl;
Mat r = Mat(10, 3, CV_8UC3);
randu(r, Scalar::all(0), Scalar::all(255));
cout << "r (OpenCV默认风格) = " << r << ";" << endl << endl;
cout << "r (Python风格) = " << format(r,"python") << ";" << endl << endl;
cout << "r (Numpy风格) = " << format(r,"numpy") << ";" << endl << endl;
cout << "r (逗号分隔风格) = " << format(r,"csv") << ";" << endl<< endl;
cout << "r (C语言风格) = " << format(r,"C") << ";" << endl << endl;
Point2f p(6, 2);
cout << "【2维点】p = " << p << ";\n" << endl;
Point3f p3f(8, 2, 0);
cout << "【3维点】p3f = " << p3f << ";\n" << endl;
vector<float> v;
v.push_back(3);
v.push_back(5);
v.push_back(7);
cout << "【基于Mat的vector】shortvec = " << Mat(v) << ";\n"<<endl;
vector<Point2f> points(20);
for (size_t i = 0; i < points.size(); ++i)
points[i] = Point2f((float)(i * 5), (float)(i % 7));
cout << "【二维点向量】points = " << points<<";";
getchar();//按任意键退出
return 0;
}
显示效果如下: