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的簡單總結。

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