10、OpenCV中影象和Mat型別(一)

Mat型別可以被認為是OpenCV庫的核心。 OpenCV庫中絕大多數的函式都是Mat類的成員,以Mat作為引數,或者Mat作為返回值。

10、OpenCV中影象和Mat型別(一)

Mat類用於表示任意維數的密集陣列。即使對於陣列中的該條目為零,也存在與該條目相對應的資料值。大多數影象都以密集陣列的形式儲存。在稀疏陣列的情況下,通常只儲存非零條目。如果許多條目都是零,那麼可以節省大量的儲存空間。使用稀疏陣列而不是密集陣列的常見情況是直方圖。對於許多直方圖,大多數條目都是零,並且儲存所有這些零不是必需的。對於稀疏陣列的情況,OpenCV有另一種資料結構,SparseMat。

如果你熟悉OpenCV庫的C介面(2。1之前的版本),您將會記住IplImage和CvMat的資料型別。 你也可能記得CvArr。 在C ++實現中,所有這些都消失了,用Mat代替。Mat類可以用於任何維數的陣列。資料被儲存在陣列中,被認為是“光柵掃描順序”的n維數字。這意味著在一維陣列中,元素是順序的。在二維陣列中,資料按行組織,每行依次出現。對於三維陣列,每個平面都是逐行填充的。

每個Mat都包含一個標誌元素,指示陣列內容,一個dims元素指示維數,rows和cols元素指示行數和列數,指向資料指標的位置陣列資料被儲存,一個類似於Ptr <>的的引用計數器。資料陣列被佈置成使得其索引由(i0,ii,。。。,iNd-1)給出的元素的地址是:

在二維陣列的簡單情況下,這可以簡化為:

&(mtxi, j)= mtx。data +mtx。step 0 *i +mtx。step 1 *j

Mat中每個資料元素本身可以是單個數字,也可以是多個數字。在多個數字的情況下,這就是多通道陣列。一個數組可能被認為是一個32位浮點數的二維三通道陣列;在這種情況下,陣列的元素是三個32位浮點數,大小為12個位元組。在記憶體中佈局時,陣列的行可能不是絕對順序的;在下一個之前可能會有小的間隙緩衝每一行。一個n維單通道陣列和一個(n-1)維多通道陣列之間的區別在於,這個填充將始終發生在整行的末尾,即元素中的通道將始終是連續的)。

可以簡單地透過例項化一個型別為Mat的變數來建立一個數組。以這種方式建立的陣列沒有大小和資料型別。但是,可以使用create()等成員函式分配資料。 create()的一個變體將多個行,多個列和一個型別作為引數,並將該陣列表示為一個二維物件。陣列的型別決定了它具有哪種元素以及通道的數量。所有這些型別都在庫中定義,並具有CV_ {8U,16S,16U,32S,32F,64F} C {1,2,3}的格式。例如,CV_32FC3意味著一個32位浮點三通道陣列。

也可以在首次分配矩陣時指定這些內容。Mat有許多建構函式,其中一個與create()具有相同的引數。例如:

cv::Mat m;

// 建立3行10列3通道32位浮點型資料

m。create( 3, 10, CV_32FC3 );

//設定第一個通道為1。0,第二個通道為0。0,第三個通道為1。0

m。setTo( cv::Scalar( 1。0f, 0。0f, 1。0f ) );

//上面的定義與下面的語句等價

Mat m( 3, 10, CV_32FC3, cv::Scalar( 1。0f, 0。0f, 1。0f ) );

Mat物件實際上是資料區域的頭,原則上它是一個完全獨立的東西。 例如,可以將一個矩陣n分配給另一個矩陣m(即,m = n)。 在這種情況下,m中的資料指標將被改變為指向與n相同的資料。 先前由m的資料元素指向的資料將被釋放。同時,它們現在共享的資料區域的引用計數器將遞增。同時將更新m成員的資料(如行,列和標誌),以準確描述m中資料指向的資料。

表1是Mat的建構函式的完整列表。但事實上,大多數時候可能使用其中的一小部分。

10、OpenCV中影象和Mat型別(一)

表1列出了Mat物件的建構函式。除了預設的建構函式之外,它們分為三個基本類別:有些需要多行和多列來建立二維陣列的類,有些使用Size物件建立,有些構造n維陣列並要求指定維數並傳入指定每個維的大小的整數陣列的指標。此外,其中一些允許初始化資料,或者透過Scalar提供初始化值(這時整個陣列將被初始化為該值),或者透過提供指向資料塊的指標來指定。在後一種情況下,只是為現有資料建立一個數據頭,不復制資料;將資料成員設定為指向由資料引數指示的資料)。

表2的複製建構函式顯示瞭如何從另一個數組建立一個數組。除了基本的複製建構函式外,還有三種方法用於從現有陣列的子區域構建陣列,以及使用某個矩陣表示式的結果初始化新矩陣的建構函式。

10、OpenCV中影象和Mat型別(一)

也可以從OpenCV2。1版之前的CvMat或IplImage結構建立新的C ++風格的Mat結構。在這種情況下,可以採用下面表3這種方式轉換。

10、OpenCV中影象和Mat型別(一)

這些建構函式可能比你剛開始認識OpenCV的時候要多得多。還有一種建構函式是模板建構函式。 這些被稱為模板建構函式是因為它們從本身就是模板的東西構建了Mat的例項。 這些建構函式允許使用任意Vec <>或Matx <>來建立具有相應維數和型別的Mat陣列,或者使用任意型別的STL向量<>物件來構造一個相同型別的陣列。表4是這種構造方式。

10、OpenCV中影象和Mat型別(一)

Mat類還提供了許多靜態成員函式來建立特定型別的常用陣列(表4-5)。 這些函式包括zero(),ones()和eye()等函式,它們分別構造一個全是零的矩陣,一個全是1矩陣的矩陣和一個單位矩陣。表5是這種構造方式

10、OpenCV中影象和Mat型別(一)

對於Mat中的資料訪問方式可以參考第6部分的說明。

有時候我們需要訪問陣列中的某一塊元素,可能是選擇一行或一列,或原始陣列的任何子區域。有很多方法可以做到這一點,表6是Mat類的成員函式,並返回呼叫它們的陣列的子部分。

10、OpenCV中影象和Mat型別(一)

這些方法中最簡單的方法是row()和col()。與row()和col()緊密相關的是rowRange()和colRange()。這些函式基本上是一樣的,只不過他們會提取一個具有多個連續行(或列)的陣列。可以透過以下兩種方式之一呼叫這兩個函式:指定一個整數開始和結束行(或列),或者透過傳遞一個行(或列)的Range物件。範圍包括開始索引但不包括結束索引。

除了從m。diag()返回的陣列引用矩陣的對角線元素之外,成員函式diag()與row()或col()的作用相同。 m。diag()需要一個整數引數,用於指示要提取哪個對角線。如果該引數為零,那麼它將是主對角線。如果是正數,則它將從陣列上半部分的主對角線偏移該距離。如果它是負數,那麼它將來自陣列的下半部分。

提取子矩陣的最後一種方法是使用operator()。使用這個運算子,你可以傳遞一對範圍(行的Range和列的Range)或者從Rect指定你想要的區域。