OpenCV作為強大的計算機視覺開源庫,很大程度上參考了MatLab的實現細節和風格,比如說,在OpenCV2.x 版本以后,越來越多的函數實現了MatLab具有的功能,甚至干脆連函數名都一模一樣(如 imread, imshow,imwriter等)。這一做法,不僅拉近了產品開發與學術研究的距離,并極大程度的提高了開發人員的研發效率,不得不說,Intel公司真的是一個偉大的公司。
在計算機內存中,數字圖像以矩陣的形式存儲和運算,比如,在MatLab中,圖像讀取之后對應一個矩陣,在OpenCV中,同樣也是如此。
在早期的OpenCV1.x版本中,圖像的處理是通過iplImage(該名稱源于Intel的另一個開源庫Intel Image PRocessing Library ,縮寫成IplImage)結構來實現的。早期的OpenCV是用C語言編寫,因此提供的借口也是C語言接口,其源代碼完全是C的編程風格。IplImage結構是OpenCV矩陣運算的基本數據結構。
到OpenCV2.x版本,OpenCV開源庫引入了面向對象編程思想,大量源代碼用C++重寫,Mat類 (Matrix的縮寫) 是OpenCV用于處理圖像而引入的一個封裝類。從功能上講,Mat類在IplImage結構的基礎上進一步增強,并且,由于引入C++高級編程特性,Mat類的擴展性大大提高,Mat類的內容在后期的版本中不斷豐富,如果你查看Mat類的定義的話(OpenCV3.1/sources/modules/core/include/opencv2/core/mat.hpp),會發現其設計實現十分全面而具體,基本覆蓋計算機視覺對于圖像處理的基本要求。
因此,在當前的OpenCV開發中,Mat可以說是最最最常見的數據單元,深入了解Mat類對于OpenCV深入開發有著重大意義。
Mat類十分龐大,其所涉及的成員函數和變量難以一一細數,在這里,僅學習記錄其最最最常見的部分,以便日常使用。
0.默認構造函數
cv::Mat::Mat()默認構造函數,生成一個矩陣并由OpenCV提供的函數(一般是Mat::create() 和 cv::imread() )來分配儲存空間。
Mat類可以分為兩個部分:矩陣頭和指向像素數據的矩陣指針
矩陣頭 包括數字圖像的矩陣尺寸、存儲方法、存儲地址和引用次數等,矩陣頭的大小是一個常數,不會隨著圖像的大小而改變,但是保存圖像像素數據的矩陣則會隨著圖像的大小而改變,通常數據量會很大,比矩陣頭大幾個數量級。這樣,在圖像復制和傳遞過程中,主要的開銷是由存放圖像像素的矩陣而引起的。因此,OpenCV使用了引用次數,當進行圖像復制和傳遞時,不再復制整個Mat數據,而只是復制矩陣頭和指向像素矩陣的指針,例如:
cv::Mat a ; //默認構造函數,創建矩陣頭a = cv::imread("test.jpg");//讀入圖像,矩陣指針指向該像素數據cv::Mat b = a ;//復制上面的a,b有各自的矩陣頭,但是其矩陣指針指向同一個矩陣,也就是其中任何一個改變了矩陣數據都會影響另外一個。 那么,多個Mat共用一個矩陣數據,最后誰來釋放矩陣數據呢? 這就是引用計數的作用,當Mat對象每被復制一次時,就會將引用計數加1,而每銷毀一個Mat對象(共用同一個矩陣數據)時引用計數會被減1,當引用計數為0時,矩陣數據會被清理。
1.常用構造函數(1)
cv::Mat::Mat(int rows,int cols,int type)重載的構造函數,這也是常用構造函數之一,在創建對象同時,提供矩陣的大?。╮ows,行數;cols ,列數),以及存儲類型(type) 該類型表示矩陣中每一個元素在計算機內存的存儲類型,如CV_8UC3,具體含義為“3通道8位無符號數”。
使用舉例:
Mat src(10,10,CV_32FC3);表示src是一個10*10的矩陣,且矩陣元素以32位float型存儲
類似,OpenCV還提供了一種Size() 數據結構來構造Mat對象
2.常用構造函數(2)
cv::Mat::Mat(Size size,int type )Size類等效于一個成對數據,size::Size(cols,rows),特別注意 cols和rows的位置
舉個例子
Mat src1(3, 4, CV_32FC3);Mat src2(Size(3, 4), CV_32FC3);cout << "src1.rows=" << src1.rows << " src1.cols=" << src1.cols <<endl;cout << "src2.rows=" << src2.rows << " src2.cols=" << src2.cols << endl;cout << "src1.size="<<src1.size() << endl <<"src2.size=" << src2.size() <<endl;輸出結果
不得不說,這個Size類的數據結構有點“反人類”,但這樣做的好處是方便了計算機內部的運算(比如OpenCV很多函數計算Size相關的數據也是按這個順序來的,具體為什么這樣,我也不太清楚,個人理解為行業標準)。
還有,我們平時所說分辨率,也是Size的類型,比如屏幕分別率 1440*900,其中cols=1440,rows=900。
3.常用構造函數(3)
cv::Mat::Mat(int ndims,const int * sizes,int type,const Scalar& s)該構造函數與使用了Scalar參數,作用是能夠通過Scalar數據類來初始化元素值,例如,我們要生成一張白色背景的圖片:
Mat src1(300, 400, CV_8UC3,Scalar(255,255,255));imshow("test", src1);運行結果
其中,(255,255,255)對應以8位無符號數存儲,RGB色域的白色值。
4.常用構造函數(4)
cv::Mat::Mat(const Mat & m)引用m矩陣,注意,這里是引用值
1.at函數 at函數的功能是訪問矩陣元素,根據不同的使用場景,有多個重載函數可供選擇。 如,訪問一個二維的矩陣,可用at函數原型為:
_Tp& cv::Mat::at(int i0,int i1)使用方法舉例:
Mat src = imread("test.jpg");int elem = src.at<int>(0,0);訪問test.jpg圖像的(0 , 0)元素
2.channels函數
int cv::Mat::channels () const返回圖像的通道數
3.clone函數
Mat cv::Mat::clone() const矩陣復制
4.convertTo函數
void cv::Mat::convertTo(OutputArray m,int rtype,double alpha = 1,double beta = 0) const轉換矩陣存儲類型,具體計算公式如下: m(x,y)=saturate_cast<rType>(α(?this)(x,y)+β)
m是輸入矩陣,rtype是目標類型,alpha是放縮系數,beta是增減標量
5.copyTo函數
void cv::Mat::copyTo(OutputArray m) const從m矩陣復制data數據單元,與clone函數的作用類似
6.create函數
void cv::Mat::create(int rows,int cols,int type)分配矩陣的存儲單元,一般和默認構造函數配合使用
7**.depth函數**
int cv::Mat::depth() const返回圖像深度,即矩陣元素的存儲方式
8.diag函數
Mat cv::Mat::diag(int d = 0) const提取矩陣的對角元素
9.mul函數
MatExpr cv::Mat::mul(InputArray m,double scale = 1 ) const矩陣的乘法
10.inv函數
MatExpr cv::Mat::inv(int method = DECOMP_LU) const求逆矩陣
11.t函數
MatExpr cv::Mat::t() const求轉置矩陣 12.total函數
size_t cv::Mat::total() const返回矩陣的元素總個數,如30*40的圖像,存在1200個像素點
OpenCV博大精深,我不過剛剛接觸,要學的東西還有很多很多很多…,繼續努力!
新聞熱點
疑難解答