cv::Mat初识和它的六种创建方法

cv::Mat 初识

  Opencv种的Mat类,使得Opencv的编程更加的简单,程序员不用过多的去关注内存管理,并且发现Opencv的编程有点像不需要太多编程技术的Matlab一样,甚至有些函数名字都是一样的。所以对Mat的了解是很有必要的。
  首先我们在处理一块数据的时候,如果使用Mat类,我们得到的好处是:

  1. 不需要手动申请一块内存;
  2. 在不需要时不用再手动释放内存;
  3. 可以通过类的封装,方便的获取到数据的相关信息。

  显然的,它利用了类的特性,将内存管理和数据信息封装在类的内部,用户只需要对Mat类对象进行数据或面向对象操作即可。
Mat类分为两个部分:矩阵头和矩阵数据。如果我们在操作一副图像的数据量时,矩阵数据的大小很大(一般约有1M的数据量),那么拷贝和赋值函数所作的操作如果的深拷贝的话,效率会大大的降低。所以,Opencv的做法是只复制其矩阵头信息,而矩阵数据采用引用的方式,即多个Mat对象共享同一个矩阵数据,这里使用的原理类似c++11中的共享指针。
  如下示例:

	cv::Mat A = cv::imread("erode.jpg");
	cv::Mat B(A);
	cv::Mat C = A;

	printf("A.data = %p\nB.data = %p\nC.data = %p\n", A.data, B.data, C.data);

  输出结果如下:

A.data = 000001F0A0BF00C0
B.data = 000001F0A0BF00C0
C.data = 000001F0A0BF00C0

  如上我们可以看到,三个Mat类对象的矩阵数据的地址是一样的。那么释放内存的原则是怎样的呢。这个也是内部使用了引用计数的方法,类似共享指针,当引用计数变为0的时候才会真正的释放内存。

cv::Mat 类对象的创建方法

  通过学习本人也总结了一些创建Mat类对象常用的几种方法,在这里也记录一下。

1. 使用构造函数

	cv::Mat M1(3, 3, CV_8UC4, cv::Scalar(0, 0, 0, 255));
	std::cout << "M1 = " << std::endl << M1 << std::endl;

  这里指定矩阵的行和列,并表示为4通道的矩阵,每个点的颜色值为(0, 0, 0, 255)。输出结果如下:

M1 =
[ 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255;
0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255;
0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255]

2. 通过数组初始化矩阵维数

	int sz[2] = { 3, 3 };
	cv::Mat M2(2, sz, CV_8UC1, cv::Scalar::all(0));
	std::cout << "M2 = " << std::endl << M2 << std::endl;

  如上,构造函数的第一个参数指定的是矩阵的维数,那么sz数组表示的是每一维数的数量,即这里表示的是3行3列。如果第一个参数是3的话,数组的大小也应该是3,表示的就是x,y,z三个维度,每个维度有3个。输出如下:

M2 =
[ 0, 0, 0;
0, 0, 0;
0, 0, 0]

3. 通过create函数来初始化

 cv::Mat M3;
 M3.create(4, 4, CV_8UC(1));
 std::cout << "M3 = " << std::endl << M3 << std::endl;

  这里是4*4的二维单通道矩阵,矩阵中的数据为随机值。如下:

[205, 205, 205, 205;
205, 205, 205, 205;
205, 205, 205, 205;
205, 205, 205, 205]

4. 通过opencv提供的类matlab的函数创建

 cv::Mat Me = cv::Mat::eye(4, 4, CV_64F);
 std::cout << "Me = " << std::endl << Me << std::endl;

 cv::Mat Mo = cv::Mat::ones(4, 4, CV_64F);
 std::cout << "Mo = " << std::endl << Mo << std::endl;

 cv::Mat Mz = cv::Mat::zeros(4, 4, CV_64F);
 std::cout << "Mz = " << std::endl << Mz << std::endl;

  eye函数表示的是单位矩阵,ones顾名思义是全是1的矩阵,zeros表示全是0的矩阵。输出如下:

Me =
[1, 0, 0, 0;
0, 1, 0, 0;
0, 0, 1, 0;
0, 0, 0, 1]
Mo =
[1, 1, 1, 1;
1, 1, 1, 1;
1, 1, 1, 1;
1, 1, 1, 1]
Mz =
[0, 0, 0, 0;
0, 0, 0, 0;
0, 0, 0, 0;
0, 0, 0, 0]

5. 数据自定义矩阵Mat创建

 cv::Mat M4 = (cv::Mat_<double>(3, 3) << 0, -1, 0, -1, 0, 0, 0, 0, 1);
 std::cout << "M4 = " << std::endl << M4 << std::endl;

  我们可以自己定义自己需要的数据量比较小的矩阵,然后通过如上的方式将其封装到cv::Mat中。如下:

M4 =
[0, -1, 0;
-1, 0, 0;
0, 0, 1]

6. 通过clone函数创建不同的Mat

 cv::Mat M5 = M4.row(1).clone();
 std::cout << "M5 = " << std::endl << M5 << std::endl;

  通过克隆函数clone获取我们需要的某一行或列的数据,这里构建出来的矩阵是深拷贝出来的Mat类对象。输出如下:

M5 =
[-1, 0, 0]

  以上,是对cv::Mat的简单总结。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章