Opencv 從c到c++ Opencv2.0版本發(fā)布后,,其新的C++接口,cv::Mat代替了原來c風(fēng)格的CvMat和IplImage.目前,,2.0版本對c的接口也是支持的,。 相對于c的接口,c++的cv::Mat統(tǒng)一了矩陣和圖像這兩個概念,。事實上,,矩陣和圖像其實是一樣的。由于cv::Mat是c++的類,,所以也具備了相關(guān)的一些特征,。例如,內(nèi)存的釋放,。在C++中,,一個對象超出其使用范圍后,會自動調(diào)用析構(gòu)函數(shù)進(jìn)行銷毀,。而在c中,,如果給CvMat類型的變量使用函數(shù)cvCreateImage 等函數(shù)分配了內(nèi)存空間,那么必須調(diào)用相應(yīng)的函數(shù)進(jìn)行釋放,,而不會自動銷毀,。如果沒有相應(yīng)的釋放,則會造成內(nèi)存泄漏,。 cv::Mat的介紹 在使用c++接口前,,先包含相應(yīng)的opencv namespace 在使用#include語句包含相應(yīng)頭文件后,使用下面語句即可包含相應(yīng)的opencv命名空間 using namespace cv; 如果沒有這個語句,,那么在這個命名空間的相關(guān)資源就需要帶上cv前綴,,如cv:Mat,表示的是使用命名空間cv中的Mat,; 而有了using namespace cv這個語句后,,就可以直接寫Mat 這個新的類型Mat支持類似于matlab風(fēng)格的矩陣代數(shù)運算,例如: Mat A=Mat(3,4,CV_32FC1); Mat B=Mat(4,3,CV_32FC1); ... //矩陣A和矩陣B的相關(guān)初始化在此忽略 ... Mat C = 2*A*B; 那么,,矩陣C是一個3*3矩陣,,是矩陣A和矩陣B做矩陣乘法后,乘上因子2的結(jié)果,。這種方式比c接口好像要更直觀一點,。 Mat還有其他對矩陣操作的方法,,例如: Mat C = C.inv(); //Now C is its own inverse matrix Mat D = A.t(); //D is the transposed matrix of A Mat的內(nèi)部結(jié)構(gòu) Mat和c風(fēng)格的CvMat和IplImage一樣,原點(origin)在左上點,,行和列的計數(shù)都是從0開始,。 矩陣Mat的聲明方法 矩陣可以有1,2,,3或者4個通道,。 最簡單的創(chuàng)建矩陣的方法是: Mat m = Mat(rows,cols,type); rows和cols分別代表矩陣的行數(shù)和列數(shù),type是矩陣的類型,與原來c風(fēng)格的是一樣,。 如果是創(chuàng)建一幅圖像,,那么推薦的方法是: Mat m = Mat(Size(width , height),type); 如果是創(chuàng)建與另外一幅圖像是等大小的,那么: Mat n = Mat(m.size() , type); 矩陣元素的訪問 訪問單通道矩陣是最簡單的,,當(dāng)然也是最重要的,。使用Mat的方法at就可以訪問位于點(i,j)的值。 Mat a= Mat(4,3, CV_32FC1); float elem_a= a.at(i,j); //獲取矩陣元素aij, i的取值范圍是 0 t到rows-1 ,,j的取值范圍是 另外,,還可以用這種方式: Point p=Point(x,y); float elem_a= a.at(p); //注意: y 的取值范圍是0 到 rows-1 , x 的取值范圍是 0 到cols-1 如果需訪問的矩陣是多通道矩陣,,可能會麻煩一點點,,但也不會太麻煩的。使用Mat的ptr方法獲取指向某一行的指針,,然后使用[ ]來訪問在特定通道上的特定值,。 type elem = matrix.ptr(i)[nChannels*j+c] 其中, type:是指矩陣的數(shù)據(jù)類型(float,double,uchar,等等) i:行號(你要訪問的是哪一行) nChannels:矩陣的通道數(shù)(矩陣是多少通道的:1,,2,,3,4) j:列號(你要訪問的是哪一列) C:通道號(你要訪問的是哪一個通道的值) 使用上面的方法,,其實也可以用來訪問單通道的矩陣,,只是nChannels的值為1,,而且c=0即可,。 矩陣的reshape 矩陣的reshape可以說是矩陣通道和矩陣的行之間的一種轉(zhuǎn)換。例如,,假設(shè)我們有一個矩陣,,它的通道數(shù)是Nc , 矩陣大小是N*1 ,,如果要把這個矩陣轉(zhuǎn)換成單通道的N*Nc大小的矩陣,,那么,使用下面的代碼即可實現(xiàn): Mat a= Mat(4,1, CV_32FC3); //a 是 4*1, 3 通道矩陣 Mat b=a.reshape(1); //b 是 4*3, 1 通道矩陣 矩陣的reshape在什么樣的場景中被用到呢,?假如我們有個一系列的point對象,,如下: vector<;Point32f>v;//假設(shè)已經(jīng)放滿了數(shù)據(jù) v里面的數(shù)據(jù)是: [(x0, y0, z0)] [(x1, y1, z1)] [(x2, y2, z2)] [(x3, y3, z3)] [(..., ..., ...)] 那么,,可以通過下面的代碼,把vector Mat m1=Mat(v, true); //boolean 變量true是表示把數(shù)據(jù)從v拷貝到m1 如果boolean 變量不是true,,那就不會是把v數(shù)據(jù)拷貝到m1,,而僅僅是將m1的數(shù)據(jù)指針指向v 通過上面的代碼后,矩陣m1里有了多行數(shù)據(jù),,準(zhǔn)確的說矩陣m1是三通道,,一列的矩陣,當(dāng)然有多行,,行數(shù)和point對象的個數(shù)一樣,,即m1.rows與v.size()是一樣的。在這種情況下,,我們可以把這個矩陣reshape成v.size行,,3列,1通道的矩陣,。如圖: reshape后,,就可以對該矩陣進(jìn)行上述的矩陣代數(shù)運算了。處理齊次笛卡兒坐標(biāo)時,,reshape是必須的一個步驟,。 c接口與c++接口的一些等價 CvSize -> Size CvVideoCapture -> VideoCapture IplImage, CvMat -> Mat cvQueryFrame -> >> (operator) cvShowImage -> imshow cvLoadImage -> imread |
|