【opencv14】cv::Mat---Desne数组类
1.cv::Mat類簡介
cv::Mat用于大型矩陣類型,這可以說是Opencv庫整個c++實現的核心類。OpenCV庫中絕大多數函數都是cv::Mat類的成員函數,或者以cv::Mat作為參數,或者以cv::Mat作為返回值。
cv::Mat類用于表示任意維度的dense數組。大多數圖像數據都是存儲在dense數組中,當然與之對應的就是sparse數組。
- dense數組:對于數組中的每個元素,內存中都存儲了一個與當前元素對應的數據值,即使該元素值為零。
- sparse數組:存儲的是非零項。如果許多元素值實際上為零,那么這會節省大量存儲空間。(Opencv中永cv::SpareseMat類表述sparse數組。)
Note:若你對opencv2.1之前的版本較熟悉,你可能記得IplImage{IplImage}IplImage,CvMat{CvMat}CvMat。但在之后的版本中,這些類都沒了,都被cv::Mat{cv::Mat}cv::Mat取代。
2.cv::Mat類中數據存儲規則
cv::Mat類數據可以被用來表示各種維度的數組。數據存儲在數組中,可以看作是一個n維的“光柵掃描順序(raster scan order)”。
raster scan order解釋:
在一維數組中,元素是順序排列的。
在二維數組中,元素是被組織成行,每一行依次排列
在三維數組中,每一個平面可以認為二維數組,且每一個平面(二維數組)按行排列,且平面是一個接著一個。
每個數組都有一個標志元素,用來指示數組的內容。
- dim:指定數組維度
- rows/cols:指定數組的行數和列數(當dim>2時,這兩個參數無效)
- 指針:指向數組數據存儲位置的數據指針
- refcount:引用計數器,類似于利用cv::Ptr<>的引用計數器。該類成員的存在使得cv::Mat類能像數據智能指針一樣被數據包含。
數據中的內存布局由數組step[]描述。cv::Mat類中,當下標為(i0,i1,’’’,iNd-1,iNd)時,數組的存儲地址為:
對于二維數組而言:
cv::Mat中的每個數據元素本身可以是單個數字,也可以是多個數字。在多個數字的情況下,這個庫稱為多通道數組。事實上,n維數組和(n-1)維多通道數組實際上是非常相似的對象,但是由于在許多情況下,將數組看作向量值數組是有用的,比如圖像而言通道為3表示彩色圖像,通道為1表示灰度圖像,所以庫中對這種結構有特殊的規定。
在使用opencv2.1之前的版本中的IplImage{IplImage}IplImage時,有一個表征通道的成員變量:IplImage : :nChannels{IplImage\::\::nChannels}IplImage::nChannels。但在之后的版本中用cv::Mat類后,沒有這個成員變量了,要查看通道數則需要調用cv::channels()。
要設置這種通道的區別的主要原因是內存訪問。根據定義,數組的元素可以是向量值的部分。例如,一個數組可以被稱為32位浮點數的二維三通道數組;在這種情況下,數組的元素是三個大小為12字節的32位浮點數。
當然在實際情況下,數據元素在內存中布局時,數組的行不是絕對按照順序連續存放的;可能在行與行之間會有小的間隔。
這種填充的目的是提高內存訪問速度。
n維單通道陣列與(n-1)維多通道陣列的區別在于,這種填充總是發生在完整行的末尾(也就是說,同一個通道中的元素總是順序連續的)。
3.創建數組
cv::Mat m; // Create data area for 3 rows and 10 columns of 3-channel 32-bit floats m.create( 3, 10, CV_32FC3 ); // Set the values in the 1st channel to 1.0, the 2nd to 0.0, and the 3rd to 1.0 m.setTo( cv::Scalar( 1.0f, 0.0f, 1.0f ) );可以利用cv::Mat類實例化一個變量來創建數組。當然利用這種方式創建的數組沒有大小,也沒有數據類型。在用這種方式創建數組后,之后可使用諸如create()這樣的成員函數來分配數組大小,數據類型等參數。數組類型這一個參數決定了它具有哪種元素。
- 第一個位置參數:傳入的是數組的行數,此例中表示數組3行
- 第二個位置參數:傳入的是數組的列數,此例中表示數組10列
- 第三個位置參數:傳入的是數組元素的類型,此例中32bit浮點數,3通道
第三個位置參數,即指定元素的基本類型,也指定通道數。所有可能的類型都在頭文件中定義了,一共有6*3=18種可選方式(從如下組合中選取):CV_{8U,16S,16U,32S,32F,64F}{1,2,3}CV\_{\{8U,16S,16U,32S,32F,64F\}\{1,2,3\}}CV_{8U,16S,16U,32S,32F,64F}{1,2,3}
所以按照上述的例子CV_32FC3表示32bit的浮點數,3通道。
如上述代碼所示,前一段介紹的代碼可以整合構造過程中,這是另一種構造函數(帶參數的)。
理解數組中的數據沒有嚴格地附加到數組對象上是至關重要的。Mat對象實際上是一個數據區域的標頭,原則上是一個完全獨立的東西。例如,可以將一個矩陣n賦值給另一個矩陣m(即m = n)。在這種情況下,m內部的數據指針將被改變為指向與n相同的數據,之前m的數據指針(如果有的話)所指向的數據將被釋放。同時,它們現在共享的數據區域的引用計數器將增加。最后,將更新m的成員(例如行,列和標志),以準確描述m中數據現在指向的數據。 這一切使得這些行為變得很方便,其中數組可以彼此分配,并且在幕后自動執行此操作以提供正確的結果。
4.cv::Mat對象的構造函數
下表是cv::Mat類可用的構造函數的完整列表。當然大部分情況下,我們只會用到下表中的某幾個。
| 默認構造函數 | cv::Mat; |
| 按類型的2維矩陣構造函數 | cv::Mat( int rows, int cols, int type ); |
| 帶初始化值的按類型的2維矩陣構造函數 | cv::Mat(int rows, int cols, int type,const Scalar& s); |
| 具有預先存在的數據的2維矩陣構造函數 | cv::Mat(int rows, int cols, int type,void* data, size_t step=AUTO_STEP); |
| 按類型的2維數組構造函數(大小以sz為單位) | cv::Mat( cv::Size sz, int type ); |
| 帶初始化值的按類型的2維矩陣構造函數(大小以sz為單位) | cv::Mat(cv::Size sz,int type, const Scalar& s); |
| 具有預先存在的數據的2維矩陣構造函數(大小以sz為單位) | cv::Mat( cv::Size sz, int type,void* data, size_t step=AUTO_STEP) |
| 按類型的多維矩陣構造函數 | cv::Mat(int ndims, const int* sizes,int type); |
| 帶初始化值的按類型的多維矩陣構造函數 | cv::Mat(int ndims, const int* sizes,int type, const Scalar& s); |
| 具有預先存在的數據的多維矩陣構造函數 | cv::Mat(int ndims, const int* sizes,int type, void* data,size_t step=AUTO_STEP); |
上表列出了cv::Mat類對象的基本構造函數,下表將列出拷貝構成函數,即如何從一個已知數組創建數組。除了基本的復制構造函數之外,還有三種方法用于從現有數組的子區域構造數組,以及一種使用某種矩陣表達式的結果初始化新矩陣的構造函數。
| 拷貝構造函數 | cv::Mat( const Mat& mat ); |
| 僅拷貝指定行列的構造函數 | cv::Mat(const Mat& mat,const cv::Range&rows,const cv::Range&cols); |
| 僅拷貝指定區域的構造函數 | cv::Mat(const Mat& mat,const cv::Rect& roi); |
| 廣義感興趣區域復制構造函數,它使用范圍數組從n維數組中進行選擇 | cv::Mat(const Mat& mat,const cv::Range*ranges); |
| 復制構造函數,用其他矩陣的代數表達式的結果初始化m | cv::Mat( const cv::MatExpr&expr ); |
上述拷貝構造函數中,利用子區域(也稱為“感興趣區域”)構造函數有三種形式:一種采用一系列行和一系列列(這僅適用于二維矩陣),一種使用cv :: Rect指定矩形子區域(也僅適用于二維矩陣),最后一個采用范圍數組。 在后一種情況下,指針參數范圍指向的有效范圍的數量必須等于數組mat的維數。 如果mat是ndim大于2的多維數組,則必須使用第三個選項。
5.與舊版本之間的兼容問題
如果您正在維護包含C樣式數據結構的opencv2.1版本之前的代碼,您可能希望從現有的CvMat或IplImage結構創建新的C ++樣式的cv :: Mat結構。 在這種情況下,我們有兩個選擇:
- 在現有的數據上構建一個標記頭m(通過將copyData設置為false)
- 重新分配內存,并將老數據復制到m中(通過將copyData設置為true)
6.模板構造函數
模板構造函數之所以被稱之為模板構造函數,不是因為它們從cv::Mat構造出了一個模板類,而是因為它們從本身就是模板的東西(cv::Vec<>或cv::Matx<>),來創建cv::Mat類實例。所以模板構造函數能夠用任意cv::Vec<>,cv::Matx<>類的實例來創建cv::Mat數組。或者將任意類型的STL庫中的vector<>實例來構建相同類型的cv::Mat數組。
| 從相同類型的cv :: Vec構造類型為T和大小為n的一維數組 | cv::Mat(const cv::Vec<T,n>&vec,bool copyData=true); |
| 從相同類型的cv :: Matx構造類型為T且大小為m×n的二維數組 | cv::Mat(const cv::Matx<T,m,n>&vec,bool copyData=true); |
| 從包含相同類型元素的STL向量構造類型為T的一維數組 | cv::Mat(const std::vector&vec,bool copyData=true); |
7.Mat類的靜態成員函數
cv::Mat類提供一些能夠創建常用類的靜態成員函數。
//創建一個大小為rows×cols的cv :: Mat,其中所有的值為類型為type(CV_32F等)的零 cv::Mat::zeros( rows, cols, type );//創建一個大小為rows×cols的cv :: Mat,其中所有的值為類型為type(CV_32F等)的一 cv::Mat::ones( rows, cols, type);//單位矩陣 cv::Mat::eye( rows, cols, type);總結
以上是生活随笔為你收集整理的【opencv14】cv::Mat---Desne数组类的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Spring ClassPathReso
- 下一篇: Spring中常用注解及其作用(二)