天天看點

c++ opencv mat_10、OpenCV中圖像和Mat類型(一)

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

c++ opencv 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的構造函數的完整清單。但事實上,大多數時候可能使用其中的一小部分。

c++ opencv mat_10、OpenCV中圖像和Mat類型(一)

表1列出了Mat對象的構造函數。除了預設的構造函數之外,它們分為三個基本類别:有些需要多行和多列來建立二維數組的類,有些使用Size對象建立,有些構造n維數組并要求指定維數并傳入指定每個維的大小的整數數組的指針。此外,其中一些允許初始化資料,或者通過Scalar提供初始化值(這時整個數組将被初始化為該值),或者通過提供指向資料塊的指針來指定。在後一種情況下,隻是為現有資料建立一個資料頭,不複制資料;将資料成員設定為指向由資料參數訓示的資料)。

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

c++ opencv mat_10、OpenCV中圖像和Mat類型(一)

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

c++ opencv mat_10、OpenCV中圖像和Mat類型(一)

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

c++ opencv mat_10、OpenCV中圖像和Mat類型(一)

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

c++ opencv mat_10、OpenCV中圖像和Mat類型(一)

對于Mat中的資料通路方式可以參考第6部分的說明。

有時候我們需要通路數組中的某一塊元素,可能是選擇一行或一列,或原始數組的任何子區域。有很多方法可以做到這一點,表6是Mat類的成員函數,并傳回調用它們的數組的子部分。

c++ opencv mat_10、OpenCV中圖像和Mat類型(一)

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

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

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

繼續閱讀