openCv學習筆記—cv::Mat學習

一、Mat簡介

    在2001年剛剛出現的時候,OpenCV基於 C 語言接口而建。爲了在內存(memory)中存放圖像,當時採用名爲IplImage 的C語言結構體,時至今日這仍出現在大多數的舊版教程和教學材料。但這種方法必須接受C語言所有的不足,這其中最大的不足要數手動內存管理,其依據是用戶要爲開闢和銷燬內存負責。雖然對於小型的程序來說手動管理內存不是問題,但一旦代碼開始變得越來越龐大,你需要越來越多地糾纏於這個問題,而不是着力解決你的開發目標。

   幸運的是,C++出現了,並且帶來類的概念,這給用戶帶來另外一個選擇:自動的內存管理(不嚴謹地說)。這是一個好消息,如果C++完全兼容C的話,這個變化不會帶來兼容性問題。爲此,OpenCV在2.0版本中引入了一個新的C++接口,利用自動內存管理給出瞭解決問題的新方法。使用這個方法,你不需要糾結在管理內存上,而且你的代碼會變得簡潔(少寫多得)。但C++接口唯一的不足是當前許多嵌入式開發系統只支持C語言。所以,當目標不是這種開發平臺時,沒有必要使用 方法(除非你是自找麻煩的受虐狂碼農)。

   關於 Mat ,首先要知道的是你不必再手動地(1)爲其開闢空間(2)在不需要時立即將空間釋放。但手動地做還是可以的:大多數OpenCV函數仍會手動地爲輸出數據開闢空間。當傳遞一個已經存在的Mat 對象時,開闢好的矩陣空間會被重用。也就是說,我們每次都使用大小正好的內存來完成任務。

   基本上講 Mat 是一個類,由兩個數據部分組成:矩陣頭(包含矩陣尺寸,存儲方法,存儲地址等信息)和一個指向存儲所有像素值的矩陣(根據所選存儲方法的不同矩陣可以是不同的維數)的指針。矩陣頭的尺寸是常數值,但矩陣本身的尺寸會依圖像的不同而不同,通常比矩陣頭的尺寸大數個數量級。因此,當在程序中傳遞圖像並創建拷貝時,大的開銷是由矩陣造成的,而不是信息頭。OpenCV是一個圖像處理庫,囊括了大量的圖像處理函數,爲了解決問題通常要使用庫中的多個函數,因此在函數中傳遞圖像是家常便飯。同時不要忘了我們正在討論的是計算量很大的圖像處理算法,因此,除非萬不得已,我們不應該拷貝 的圖像,因爲這會降低程序速度。

二、Mat的基本操作

   這裏展示一個例子解釋一下Mat的基本操作

  1. <strong>#include<cv.h>  
  2. #include<highgui.h>  
  3. #include<iostream>  
  4. using namespace cv;  
  5. using namespace std;  
  6. int main()  
  7. {  
  8.     /*********************************Mat基本操作-矩陣*******************************************/  
  9.     //二維三通道矩陣建立  
  10.     Mat M(2,2, CV_8UC3, Scalar(0,0,255)); //使用構造函數創建矩陣  
  11.     /* 
  12.     CV_8UC3 表示使用8位的 unsigned char 型,每個像素由三個元素組成三通道,初始化爲(0,0,255) 
  13.     */  
  14.     cout << "M = " << endl << " " << M << endl << endl; //格式化輸出  
  15.     //三維  
  16.     int sz[3] = {3,3,3};   
  17.     Mat L(3,sz, CV_8UC(1), Scalar::all(0));  
  18.     /* 
  19.     超過兩維的矩陣:指定維數,然後傳遞一個指向一個數組的指針,這個數組包含每個維度的尺寸;其餘的相同 
  20.     */  
  21.     cout << "L = " << endl << " " << M << endl << endl; //格式化輸出  
  22.   
  23.     /********************************************Mat基本操作-圖像*******************************/  
  24.     Mat A, C;      // 只創建信息頭部分  
  25.     A=imread("D:\\openCV\\openCVProject\\openCv筆記\\openCv筆記\\test.jpg", CV_LOAD_IMAGE_COLOR); // 這裏爲矩陣開闢內存  
  26.     Mat B(A);                // 使用拷貝構造函數  
  27.     C = A;                  // 賦值運算符  
  28.     /* 
  29.     拷貝構造函數和賦值函數 只拷貝信息頭和矩陣指針 
  30.     */  
  31.   
  32.     Mat D (A, Rect(10, 10, 100, 100) ); //選取A中一個矩形區域,即只訪問其矩形區域的信息頭,只是創建信息頭  
  33.     Mat E = A(cv::Range::all(), Range(1,3)); // 創建訪問邊界的信息頭。  
  34.     /* 
  35.     要創建一個感興趣區域( ROI ),你只需要創建包含邊界信息的信息頭 
  36.     */  
  37.   
  38.     Mat F = A.clone();//複製圖像,包括數據  
  39.     Mat G;  
  40.     A.copyTo(G);  
  41.     /* 
  42.     拷貝矩陣本身(不只是信息頭和矩陣指針), 
  43.     */  
  44.   
  45.     //測試  
  46.     namedWindow( "a", CV_WINDOW_AUTOSIZE );  
  47.     namedWindow( "c", CV_WINDOW_AUTOSIZE );  
  48.       
  49.     imshow( "a", D);  
  50.     imshow( "c", E );  
  51.   
  52.       
  53.     /****************************************圖像的讀取、處理和保存**************************************/  
  54.       Mat image;  
  55.      image = imread( "D:\\openCV\\openCVProject\\openCv筆記\\openCv筆記\\test.jpg", CV_LOAD_IMAGE_COLOR);//導入圖像  
  56.   
  57.      if( !image.data )  
  58.      {  
  59.         cout<< " No image data \n " ;  
  60.         return -1;  
  61.      }  
  62.   
  63.      Mat gray_image;  
  64.      cvtColor( image, gray_image, CV_BGR2GRAY );//轉化爲灰度圖  
  65.   
  66.      imwrite( "../../images/Gray_Image.jpg", gray_image );//寫入圖像  
  67.   
  68.      namedWindow( "source", CV_WINDOW_AUTOSIZE );  
  69.      namedWindow( "Gray image", CV_WINDOW_AUTOSIZE );  
  70.   
  71.      imshow( "source", image );  
  72.      imshow( "Gray image", gray_image );  
  73.      /*******************************************************************************************/  
  74.      waitKey(0);  
  75.      return 0;  
  76. }</strong>  

  對於Mat數據結構,在對圖像進行處理時要注意:

 

OpenCV函數中輸出圖像的內存分配是自動完成的(如果不特別指定的話)。 使用OpenCV的C++接口時不需要考慮內存釋放問題。 賦值運算符和拷貝構造函數( ctor )只拷貝信息頭。 使用函數 clone() 或者copyTo() 來拷貝一副圖像的矩陣

 

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