我在學《數據結構》的時候,每接觸一種新的ADT(abstract data type, 抽象數據類型 ),一般的套路都是這樣的—— 1.先了解ADT的結構,如何定義?包括哪些數據對象?如,線性表是n個具有相同特性的數據元素的有限序列。 2.再學習基于該ADT結構的一些操作和算法。如,線性表的增刪查改,基于順序表的排序算法; 3.最后再學習該ADT的存儲方式和實現過程。如,鏈表在計算機內存中的存儲。
那么,在了解了基本結構之后,作為OpenCV最重要的ADT——Mat類,在計算中如何存儲,以及有哪些基本操作的呢?
Mat類是一個n維單通道或多通道的稠密型數值陣列,可以用于存儲實數或者負數向量和矩陣(real or complex-valued vectors or matrices)、灰度圖和彩色圖(grayscale or color images )、矢量場(vector fields)等,陣列M的數據分布取決于數組M.step[],因此M陣列中元素(i0,...,iM.dims?1)
的地址可以計算為:
其中, step[i]是Mat類中十分重要的一個屬性,表示第i維的總大小,單位字節 M.data指向存儲這列的首地址(類似于數組名) M.dims是總維度
例如,二維矩陣的尋址可以表示為:
addr(Mi,j)=M.data+M.step[0]?i+M.step[1]?j注意, M.step[i] >= M.step[i+1] ,實際上, M.step[i] >= M.step[i+1]* M.size[i+1],其中,M.size[i]表示第i維包含的個數,這也就意味著,二維矩陣是按行存儲(stored row-by-row),而三維矩陣是按面存儲(stored plane-by-plane),高維以此類推。M.size[M.dims-1]表示矩陣的最低維,大小與M.elemSize() 相等。
舉個例子,來說明矩陣的存儲方式,以及矩陣各個屬性的意義——
int sizeMat[] = { 3, 4, 6 };Mat src(3, sizeMat, CV_32FC3, Scalar::all(0));cout << "src.dims = " << src.dims << endl;cout << "src.step[0] = " << src.step[0] << endl;cout << "src.step[1] = " << src.step[1] << endl;cout << "src.step[2] = " << src.step[2] << endl << endl;cout << "src.size[0] = " << src.size[0] << endl;cout << "src.size[1] = " << src.size[1] << endl;cout << "src.size[2] = " << src.size[2] << endl << endl;cout << "src.step1[0] = " << src.step1(0) << endl;cout << "src.step1[1] = " << src.step1(1) << endl;cout << "src.step1[2] = " << src.step1(2) << endl << endl;cout << "src.elemSize() = " << src.elemSize() << endl;cout << "src.elemSize1() = " << src.elemSize1() << endl;創建一個3維的矩陣,尺寸為 3 * 4 * 6,那么輸出為
Mat類型維度是從高維度到低維度排列的,比如3維矩陣,按照面、行、點的順序對應其維度大小,我們上面所定義的矩陣包含3個面、每個面包含4行,每行包含6個點。
因此,step[0]表示第一維,面( plane),所包含總元素的字節大小
我們定義的矩陣每個面有4*6=24個點,每個點定義為CV_32FC3類型,即3通道的32位float型,一個元素包含3個float,即 3 *4=12字節,那么整個面的大小就為 24 *12 =288 字節
同理,step[1]表示第二維,行( row) ,所包含總元素的大小
step[1] = 6 *12 =72 字節
step[2]表示第三維,點( point) ,所包含總元素大小
step[2] = 12字節
step1(i)表示第i維的包含的通道數 第一維,包含4 * 6個點, 每個點都是3通道的,因此,第一維包含4 * 6 * 3 =72個通道 同理,第二維包含 18個通道,第三維包含3個通道
屬性size表示每個維度的大小,即—— 第一維大小為3,size(0) = 3 第二維為4,size(1) = 4 第三維為6,size(2) = 6
屬性elemSize表示的是每一個矩陣元素的大小,這個元素可能包含多個通道,而elemSize1表示的是每個通道下所包含基本類型的大小,即elemSize=channels * elemSize1
最后再通過一張圖來表示Mat類的尋址方式
Mat的成員函數at()是一個模板函數,針對不同的情況,有多個重載函數可供選擇,在這里,我們使用最常見的二維矩陣的at函數
for (int r = 0; r < src.rows; r++) { for (int c = 0; c < src.cols; c++) { cout<< src.at<Vec3f>(r,c)<<endl; } }注意,使用at函數時,應該知道矩陣元素的類型和通道數,根據矩陣元素類型和通道數來確定at函數傳遞的類型,在上例當中,我們定義的src矩陣是CV_32FC3,即3通道float型,對應Vec3f可以兼容該類型。
注意,ptr 是指向矩陣的行,同樣,使用ptr函數也應該知道矩陣元素的類型和通道數
[1] https://www.douban.com/note/265479171/
[2] http://blog.csdn.net/qianqing13579/article/details/45318279
[3] http://blog.csdn.net/bendanban/article/details/30527785
新聞熱點
疑難解答