OpenCV作為強(qiáng)大的計(jì)算機(jī)視覺(jué)開(kāi)源庫(kù),很大程度上參考了MatLab的實(shí)現(xiàn)細(xì)節(jié)和風(fēng)格,比如說(shuō),在OpenCV2.x 版本以后,越來(lái)越多的函數(shù)實(shí)現(xiàn)了MatLab具有的功能,甚至干脆連函數(shù)名都一模一樣(如 imread, imshow,imwriter等)。這一做法,不僅拉近了產(chǎn)品開(kāi)發(fā)與學(xué)術(shù)研究的距離,并極大程度的提高了開(kāi)發(fā)人員的研發(fā)效率,不得不說(shuō),Intel公司真的是一個(gè)偉大的公司。
在計(jì)算機(jī)內(nèi)存中,數(shù)字圖像以矩陣的形式存儲(chǔ)和運(yùn)算,比如,在MatLab中,圖像讀取之后對(duì)應(yīng)一個(gè)矩陣,在OpenCV中,同樣也是如此。
在早期的OpenCV1.x版本中,圖像的處理是通過(guò)iplImage(該名稱(chēng)源于Intel的另一個(gè)開(kāi)源庫(kù)Intel Image PRocessing Library ,縮寫(xiě)成IplImage)結(jié)構(gòu)來(lái)實(shí)現(xiàn)的。早期的OpenCV是用C語(yǔ)言編寫(xiě),因此提供的借口也是C語(yǔ)言接口,其源代碼完全是C的編程風(fēng)格。IplImage結(jié)構(gòu)是OpenCV矩陣運(yùn)算的基本數(shù)據(jù)結(jié)構(gòu)。
到OpenCV2.x版本,OpenCV開(kāi)源庫(kù)引入了面向?qū)ο缶幊趟枷?,大量源代碼用C++重寫(xiě),Mat類(lèi) (Matrix的縮寫(xiě)) 是OpenCV用于處理圖像而引入的一個(gè)封裝類(lèi)。從功能上講,Mat類(lèi)在IplImage結(jié)構(gòu)的基礎(chǔ)上進(jìn)一步增強(qiáng),并且,由于引入C++高級(jí)編程特性,Mat類(lèi)的擴(kuò)展性大大提高,Mat類(lèi)的內(nèi)容在后期的版本中不斷豐富,如果你查看Mat類(lèi)的定義的話(OpenCV3.1/sources/modules/core/include/opencv2/core/mat.hpp),會(huì)發(fā)現(xiàn)其設(shè)計(jì)實(shí)現(xiàn)十分全面而具體,基本覆蓋計(jì)算機(jī)視覺(jué)對(duì)于圖像處理的基本要求。

因此,在當(dāng)前的OpenCV開(kāi)發(fā)中,Mat可以說(shuō)是最最最常見(jiàn)的數(shù)據(jù)單元,深入了解Mat類(lèi)對(duì)于OpenCV深入開(kāi)發(fā)有著重大意義。
Mat類(lèi)十分龐大,其所涉及的成員函數(shù)和變量難以一一細(xì)數(shù),在這里,僅學(xué)習(xí)記錄其最最最常見(jiàn)的部分,以便日常使用。
0.默認(rèn)構(gòu)造函數(shù)
cv::Mat::Mat()默認(rèn)構(gòu)造函數(shù),生成一個(gè)矩陣并由OpenCV提供的函數(shù)(一般是Mat::create() 和 cv::imread() )來(lái)分配儲(chǔ)存空間。
Mat類(lèi)可以分為兩個(gè)部分:矩陣頭和指向像素?cái)?shù)據(jù)的矩陣指針
矩陣頭 包括數(shù)字圖像的矩陣尺寸、存儲(chǔ)方法、存儲(chǔ)地址和引用次數(shù)等,矩陣頭的大小是一個(gè)常數(shù),不會(huì)隨著圖像的大小而改變,但是保存圖像像素?cái)?shù)據(jù)的矩陣則會(huì)隨著圖像的大小而改變,通常數(shù)據(jù)量會(huì)很大,比矩陣頭大幾個(gè)數(shù)量級(jí)。這樣,在圖像復(fù)制和傳遞過(guò)程中,主要的開(kāi)銷(xiāo)是由存放圖像像素的矩陣而引起的。因此,OpenCV使用了引用次數(shù),當(dāng)進(jìn)行圖像復(fù)制和傳遞時(shí),不再?gòu)?fù)制整個(gè)Mat數(shù)據(jù),而只是復(fù)制矩陣頭和指向像素矩陣的指針,例如:
cv::Mat a ; //默認(rèn)構(gòu)造函數(shù),創(chuàng)建矩陣頭a = cv::imread("test.jpg");//讀入圖像,矩陣指針指向該像素?cái)?shù)據(jù)cv::Mat b = a ;//復(fù)制上面的a,b有各自的矩陣頭,但是其矩陣指針指向同一個(gè)矩陣,也就是其中任何一個(gè)改變了矩陣數(shù)據(jù)都會(huì)影響另外一個(gè)。 那么,多個(gè)Mat共用一個(gè)矩陣數(shù)據(jù),最后誰(shuí)來(lái)釋放矩陣數(shù)據(jù)呢? 這就是引用計(jì)數(shù)的作用,當(dāng)Mat對(duì)象每被復(fù)制一次時(shí),就會(huì)將引用計(jì)數(shù)加1,而每銷(xiāo)毀一個(gè)Mat對(duì)象(共用同一個(gè)矩陣數(shù)據(jù))時(shí)引用計(jì)數(shù)會(huì)被減1,當(dāng)引用計(jì)數(shù)為0時(shí),矩陣數(shù)據(jù)會(huì)被清理。
1.常用構(gòu)造函數(shù)(1)
cv::Mat::Mat(int rows,int cols,int type)重載的構(gòu)造函數(shù),這也是常用構(gòu)造函數(shù)之一,在創(chuàng)建對(duì)象同時(shí),提供矩陣的大?。╮ows,行數(shù);cols ,列數(shù)),以及存儲(chǔ)類(lèi)型(type) 該類(lèi)型表示矩陣中每一個(gè)元素在計(jì)算機(jī)內(nèi)存的存儲(chǔ)類(lèi)型,如CV_8UC3,具體含義為“3通道8位無(wú)符號(hào)數(shù)”。
使用舉例:
Mat src(10,10,CV_32FC3);表示src是一個(gè)10*10的矩陣,且矩陣元素以32位float型存儲(chǔ)
類(lèi)似,OpenCV還提供了一種Size() 數(shù)據(jù)結(jié)構(gòu)來(lái)構(gòu)造Mat對(duì)象
2.常用構(gòu)造函數(shù)(2)
cv::Mat::Mat(Size size,int type )Size類(lèi)等效于一個(gè)成對(duì)數(shù)據(jù),size::Size(cols,rows),特別注意 cols和rows的位置
舉個(gè)例子
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;輸出結(jié)果

不得不說(shuō),這個(gè)Size類(lèi)的數(shù)據(jù)結(jié)構(gòu)有點(diǎn)“反人類(lèi)”,但這樣做的好處是方便了計(jì)算機(jī)內(nèi)部的運(yùn)算(比如OpenCV很多函數(shù)計(jì)算Size相關(guān)的數(shù)據(jù)也是按這個(gè)順序來(lái)的,具體為什么這樣,我也不太清楚,個(gè)人理解為行業(yè)標(biāo)準(zhǔn))。
還有,我們平時(shí)所說(shuō)分辨率,也是Size的類(lèi)型,比如屏幕分別率 1440*900,其中cols=1440,rows=900。
3.常用構(gòu)造函數(shù)(3)
cv::Mat::Mat(int ndims,const int * sizes,int type,const Scalar& s)該構(gòu)造函數(shù)與使用了Scalar參數(shù),作用是能夠通過(guò)Scalar數(shù)據(jù)類(lèi)來(lái)初始化元素值,例如,我們要生成一張白色背景的圖片:
Mat src1(300, 400, CV_8UC3,Scalar(255,255,255));imshow("test", src1);運(yùn)行結(jié)果 
其中,(255,255,255)對(duì)應(yīng)以8位無(wú)符號(hào)數(shù)存儲(chǔ),RGB色域的白色值。
4.常用構(gòu)造函數(shù)(4)
cv::Mat::Mat(const Mat & m)引用m矩陣,注意,這里是引用值
1.at函數(shù) at函數(shù)的功能是訪問(wèn)矩陣元素,根據(jù)不同的使用場(chǎng)景,有多個(gè)重載函數(shù)可供選擇。 如,訪問(wèn)一個(gè)二維的矩陣,可用at函數(shù)原型為:
_Tp& cv::Mat::at(int i0,int i1)使用方法舉例:
Mat src = imread("test.jpg");int elem = src.at<int>(0,0);訪問(wèn)test.jpg圖像的(0 , 0)元素
2.channels函數(shù)
int cv::Mat::channels () const返回圖像的通道數(shù)
3.clone函數(shù)
Mat cv::Mat::clone() const矩陣復(fù)制
4.convertTo函數(shù)
void cv::Mat::convertTo(OutputArray m,int rtype,double alpha = 1,double beta = 0) const轉(zhuǎn)換矩陣存儲(chǔ)類(lèi)型,具體計(jì)算公式如下: m(x,y)=saturate_cast<rType>(α(?this)(x,y)+β) m是輸入矩陣,rtype是目標(biāo)類(lèi)型,alpha是放縮系數(shù),beta是增減標(biāo)量
5.copyTo函數(shù)
void cv::Mat::copyTo(OutputArray m) const從m矩陣復(fù)制data數(shù)據(jù)單元,與clone函數(shù)的作用類(lèi)似
6.create函數(shù)
void cv::Mat::create(int rows,int cols,int type)分配矩陣的存儲(chǔ)單元,一般和默認(rèn)構(gòu)造函數(shù)配合使用
7**.depth函數(shù)**
int cv::Mat::depth() const返回圖像深度,即矩陣元素的存儲(chǔ)方式
8.diag函數(shù)
Mat cv::Mat::diag(int d = 0) const提取矩陣的對(duì)角元素
9.mul函數(shù)
MatExpr cv::Mat::mul(InputArray m,double scale = 1 ) const矩陣的乘法
10.inv函數(shù)
MatExpr cv::Mat::inv(int method = DECOMP_LU) const求逆矩陣
11.t函數(shù)
MatExpr cv::Mat::t() const求轉(zhuǎn)置矩陣 12.total函數(shù)
size_t cv::Mat::total() const返回矩陣的元素總個(gè)數(shù),如30*40的圖像,存在1200個(gè)像素點(diǎn)
OpenCV博大精深,我不過(guò)剛剛接觸,要學(xué)的東西還有很多很多很多…,繼續(xù)努力!
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注