OpenCV Mat 简介
OpenCV Mat 簡介
Part I
Mat是OpenCV最基本的數據結構,Mat即矩陣(Matrix)的縮寫,Mat數據結構主要包含2部分:Header和Pointer。Header中主要包含矩陣的大小,存儲方式,存儲地址等信息;Pointer中存儲指向像素值的指針。我們在讀取圖片的時候就是將圖片定義為Mat類型,其重載的構造函數一大堆,
class CV_EXPORTS Mat { public://! default constructorMat();//! constructs 2D matrix of the specified size and type// (_type is CV_8UC1, CV_64FC3, CV_32SC(12) etc.)Mat(int _rows, int _cols, int _type);Mat(Size _size, int _type);//! constucts 2D matrix and fills it with the specified value _s.Mat(int _rows, int _cols, int _type, const Scalar& _s);Mat(Size _size, int _type, const Scalar& _s);//! constructs n-dimensional matrixMat(int _ndims, const int* _sizes, int _type);Mat(int _ndims, const int* _sizes, int _type, const Scalar& _s);//! copy constructorMat(const Mat& m);//! constructor for matrix headers pointing to user-allocated dataMat(int _rows, int _cols, int _type, void* _data, size_t _step=AUTO_STEP);Mat(Size _size, int _type, void* _data, size_t _step=AUTO_STEP);Mat(int _ndims, const int* _sizes, int _type, void* _data, const size_t* _steps=0);//! creates a matrix header for a part of the bigger matrixMat(const Mat& m, const Range& rowRange, const Range& colRange=Range::all());Mat(const Mat& m, const Rect& roi);Mat(const Mat& m, const Range* ranges);//! converts old-style CvMat to the new matrix; the data is not copied by defaultMat(const CvMat* m, bool copyData=false);//! converts old-style CvMatND to the new matrix; the data is not copied by defaultMat(const CvMatND* m, bool copyData=false);//! converts old-style IplImage to the new matrix; the data is not copied by defaultMat(const IplImage* img, bool copyData=false);......}要了解如何初始化Mat結構,就應該了解它的構造函數,比如程序中的第一初始化方式調用額就是
Mat(int _rows, int _cols, int _type, const Scalar& _s);這個構造函數。
IplImage*是C語言操作OpenCV的數據結構,在當時C操縱OpenCV的時候,地位等同于Mat,OpenCV為其提供了一個接口,很方便的直接將IplImage轉化為Mat,即使用構造函數
Mat(const IplImage* img, bool copyData=false);上面程序中的第二種方法就是使用的這個構造函數。
關于Mat數據復制:前面說過Mat包括頭和數據指針,當使用Mat的構造函數初始化的時候,會將頭和數據指針復制(注意:只是指針復制,指針指向的地址不會復制),若要將數據也復制,則必須使用copyTo或clone函數
Mat還有幾個常用的成員函數,在之后的文章中將會使用到:
//! returns true iff the matrix data is continuous // (i.e. when there are no gaps between successive rows). // similar to CV_IS_MAT_CONT(cvmat->type) bool isContinuous() const;這了解上面的函數作用前,得了解下OpenCV中存儲像素的方法,如下,灰度圖(單通道)存儲按行列存儲,
三通道RGB存儲方式如下,每列含有三個通道,
為了加快訪問的速度,openCV往往會在內存中將像素數據連續地存儲成一行,isContinus()函數的作用就是用于判斷是否連續存儲成一行。存儲成一行有什么好處呢?給定這行的頭指針p,則只要使用p++操作就能逐個訪問數據。
因此當判斷存放在一行的時候,可以通過數據指針++很容易遍歷圖像像素:
long nRows = M.rows * M.channels(); // channels()也是Mat中一個常用的函數,用于獲取通道數(RGB=3,灰度=1) long nCols = M.cols; uchar *p = M.data; // 數據指針 if(M.isContinuous()) {nCols *= nRows;for (long i=0; i < nCols; i++) {*p++ = ...; // 像素賦值或讀取操作} }請注意以上幾個常用的Mat成員遍歷和函數:
M.row; // 返回圖像行數 M.nCols; // 返回圖像列數 M.channels(); //返回通道數 M.isContinuous(); // 返回bool類型表示是否連續存儲程序示例
左邊是矩陣的一些操作輸出結果,右邊的圖是通過IplImage *結構讀入,轉換為Mat后顯示結果。
Part II
Mat的作用
The class Mat represents an n-dimensional dense numerical single-channel or multi-channel array. It can be used to store real or complex-valued vectors and matrices, grayscale or color images, voxel volumes, vector fields, point clouds, tensors, histograms (though, very high-dimensional histograms may be better stored in a SparseMat ).
上面的一段話引用自官方的文檔,Mat類用于表示一個多維的單通道或者多通道的稠密數組。能夠用來保存實數或復數的向量、矩陣,灰度或彩色圖像,立體元素,點云,張量以及直方圖(高維的直方圖使用SparseMat保存比較好)。簡而言之,Mat就是用來保存多維的矩陣的。
Mat的常見屬性
- data? uchar型的指針。Mat類分為了兩個部分:矩陣頭和指向矩陣數據部分的指針,data就是指向矩陣數據的指針。
- dims 矩陣的維度,例如5*6矩陣是二維矩陣,則dims=2,三維矩陣dims=3.
- rows? 矩陣的行數
- cols?? 矩陣的列數
- size 矩陣的大小,size(cols,rows),如果矩陣的維數大于2,則是size(-1,-1)
- channels 矩陣元素擁有的通道數,例如常見的彩色圖像,每一個像素由RGB三部分組成,則channels = 3
下面的幾個屬性是和Mat中元素的數據類型相關的。
- type
表示了矩陣中元素的類型以及矩陣的通道個數,它是一系列的預定義的常量,其命名規則為CV_(位數)+(數據類型)+(通道數)。具體的有以下值:
這里U(unsigned integer)表示的是無符號整數,S(signed integer)是有符號整數,F(float)是浮點數。CV_8UC1 CV_8UC2 CV_8UC3 CV_8UC4 CV_8SC1 CV_8SC2 CV_8SC3 CV_8SC4 CV_16UC1 CV_16UC2 CV_16UC3 CV_16UC4 CV_16SC1 CV_16SC2 CV_16SC3 CV_16SC4 CV_32SC1 CV_32SC2 CV_32SC3 CV_32SC4 CV_32FC1 CV_32FC2 CV_32FC3 CV_32FC4 CV_64FC1 CV_64FC2 CV_64FC3 CV_64FC4
例如:CV_16UC2,表示的是元素類型是一個16位的無符號整數,通道為2.
C1,C2,C3,C4則表示通道是1,2,3,4
type一般是在創建Mat對象時設定,如果要取得Mat的元素類型,則無需使用type,使用下面的depth - depth
矩陣中元素的一個通道的數據類型,這個值和type是相關的。例如 type為 CV_16SC2,一個2通道的16位的有符號整數。那么,depth則是CV_16S。depth也是一系列的預定義值,
將type的預定義值去掉通道信息就是depth值:
CV_8U CV_8S CV_16U CV_16S CV_32S CV_32F CV_64F - elemSize
矩陣一個元素占用的字節數,例如:type是CV_16SC3,那么elemSize = 3 * 16 / 8 = 6 bytes - elemSize1
矩陣元素一個通道占用的字節數,例如:type是CV_16CS3,那么elemSize1 = 16? / 8 = 2 bytes = elemSize / channels
下面是一個示例程序,具體說明Mat的各個屬性:
Mat img(3, 4, CV_16UC4, Scalar_<uchar>(1, 2, 3, 4));cout << img << endl;cout << "dims:" << img.dims << endl;cout << "rows:" << img.rows << endl;cout << "cols:" << img.cols << endl;cout << "channels:" << img.channels() << endl;cout << "type:" << img.type() << endl;cout << "depth:" << img.depth() << endl;cout << "elemSize:" << img.elemSize() << endl;cout << "elemSize1:" << img.elemSize1() << endl;首先創建了一個3*4的具有4個通道的矩陣,其元素類型是CV_16U。Scalar_是一個模板向量,用來初始化矩陣的每個像素,因為矩陣具有4個通道,Scalar_有四個值。其運行結果:
運行結果首先打印了Mat中的矩陣,接著是Mat的各個屬性。注意其type = 26,而depth = 2。這是由于上面所說的各種預定義類型
例如,CV_16UC4,CV_8U是一些預定義的常量。
step
Mat中的step是一個MStep的一個實例。其聲明如下:
struct CV_EXPORTS MStep{MStep();MStep(size_t s);const size_t& operator[](int i) const;size_t& operator[](int i);operator size_t() const;MStep& operator = (size_t s);size_t* p;size_t buf[2];protected:MStep& operator = (const MStep&);};從其聲明中可以看出,MStep和size_t有比較深的關系。用size_t作為參數的構造函數和重載的賦值運算符
MStep(size_t s); MStep& operator = (size_t s);向size_t的類型轉換以及重載的[ ]運算符返回size_t
const size_t& operator[](int i) const;size_t& operator[](int i);size_t的數組以及指針?
size_t* p;size_t buf[2];那么size_t又是什么呢,看代碼
typedef unsigned int size_t;size_t就是無符號整數。
再看一下MStep的構造函數,就可以知道其究竟保存的是什么了。
inline Mat::MStep::MStep(size_t s) { p = buf; p[0] = s; p[1] = 0; }從MStep的定義可以知道,buff是一個size_t[2],而p是size_t *,也就是可以把MStep看做一個size_t[2]。那么step中保存的這個size_t[2]和Mat中的數據有何種關系呢。
step[0]是矩陣中一行元素的字節數。
step[1]是矩陣中一個元素的自己數,也就是和上面所說的elemSize相等。
上面說到,Mat中一個uchar* data指向矩陣數據的首地址,而現在又知道了每一行和每一個元素的數據大小,就可以快速的訪問Mat中的任意元素了。下面公式:
step1
規整化的step,值為step / elemSize1。 定義如下:
inline size_t Mat::step1(int i) const { return step.p[i]/elemSize1(); }仍以上例代碼中定義的img為例,來看下step,step1具體的值:
img(3*4)的type是CV_16UC4,step[0]是其一行所占的數據字節數4 *4 * 16 / 8? = 32.
step[1] 是一個元素所占的字節數,img的一個元素具有4個通道,故:4 * 16 / 8 = 2
step1 = step / elemSize1,elemSize1是元素的每個通道所占的字節數。
N維的step(N > 2)
上面分析step是一個size_t[2],實際不是很正確,正確的來說step應該是size_t[dims],dims是Mat的維度,所以對于上面的二維的Mat來說,step是size_t[2]也是正確的。
下面就對三維的Mat數據布局以及step(維度大于3的就算了吧)。
上圖引用自http://ggicci.blog.163.com/blog/static/210364096201261052543349/? 搜集資料時發現了這幅圖,一切就變的簡單了? 感謝作者Ggicci
三維的數據在Mat中是按面來存儲的,上圖描述的很清晰,這里不再多說。
上面言道,step是一個size_t[dims],dims是維度。so,三維的step就是size_t[3]。其余的不多說了,看圖就有了。下面來創建一個三維的Mat,實際看看
首先創建一個3*3*3,depth為CV_16S的兩通道的Mat
step[0]是一個數據面的大小? 3 * 3 * (16 / 8 ) * 2 = 36
step[1]是一行數據的大小 3 * (16 / 8 ) * 2 = 12
step[2]是一個元素的大小 2 * (16 / 8) = 4
PS: 三維的Mat 不能使用 <<運算符進行輸出的。
Part III
- 綜述
Mat類可以被看做是OpenCV中C++版本的矩陣類,替代原來C版本的矩陣結構體CvMat和圖像結構體IplImage;
Mat最大的優勢跟STL的兼容性很好,有很多類似于STL的操作。但是Mat遠遠強于后者;
Mat是一種高效的數據類型,它對內存進行動態的管理,不需要之前用戶手動的管理內存。
- Mat類定義
Mat類定義于core.hpp中,主要包含有兩部分數據:一部分是矩陣頭(matrix header),這部分的大小是固定的,包含矩陣的大小,存儲的方式,矩陣存儲的地址等等;另一個部分是一個指向矩陣包含像素值的指針(data)。Mat類的定義如下:
[cpp] view plaincopy- Mat數據類型
Mat的存儲是逐行存儲的,矩陣中的數據類型包括:Mat_<uchar>對應的是CV_8U,Mat_<uchar>對應的是CV_8U,Mat_<char>對應的是CV_8S,Mat_<int>對應的是CV_32S,Mat_<float>對應的是CV_32F,Mat_<double>對應的是CV_64F,對應的數據深度如下:
? CV_8U - 8-bit unsigned integers ( 0..255 )
? CV_8S - 8-bit signed integers ( -128..127 )
? CV_16U - 16-bit unsigned integers ( 0..65535 )
? CV_16S - 16-bit signed integers ( -32768..32767 )
? CV_32S - 32-bit signed integers ( -2147483648..2147483647 )
? CV_32F - 32-bit ?oating-point numbers ( -FLT_MAX..FLT_MAX, INF, NAN )
? CV_64F - 64-bit ?oating-point numbers ( -DBL_MAX..DBL_MAX, INF, NAN )
- 創建Mat矩陣
- 復制矩陣
- 合并矩陣
- 訪問矩陣元素
- Mat類成員函數詳解
Mat::eye
返回一個恒等指定大小和類型矩陣。
C++: static MatExpr Mat::eye(int rows, int cols, inttype)
C++: static MatExpr Mat::eye(Size size, int type)
參數
rows?–的行數。
cols– 的列數。
size?–替代矩陣大小規格Size(cols, rows)的方法。
type?– 創建的矩陣的類型。
該方法返回 Matlab 式恒等矩陣初始值設定項,類似 Mat::zeros()和 Mat::ones(),你可以用縮放操作高效地創建縮放的恒等矩陣:
/ / 創建4 x 4 的對角矩陣并在對角線上以0.1的比率縮小。
Mat A = Mat::eye(4, 4, CV_32F)*0.1;
Mat::create
分配新的陣列數據 (如果需要)。
C++: void Mat::create(int rows, int cols, int type)
C++: void Mat::create(Size size, int type)
C++: void Mat::create(int ndims, const int* sizes, inttype)
參數
ndims?– 新數組的維數。
rows?–新的行數。
cols?– 新的列數。
size?– 替代新矩陣大小規格:Size(cols, rows)。
sizes?– 指定一個新的陣列形狀的整數數組。
type?– 新矩陣的類型。
這是關鍵的Mat方法之一。大多數新樣式 OpenCV 函數和產生陣列的方法每個輸出數組都調用這個方法。此方法使用如下算法:
1.如果當前數組形狀和類型匹配新的請立即返回。否則,通過調用 Mat::release()取消引用以前的數據。
2.初始化新矩陣頭。
3.分配新的 total()*elemSize() 個字節的數據空間。
4.分配新的關聯數據的引用計數并將其設置為 1。
這項計劃使內存管理強大高效同時還為用戶減少了額外輸入。這意味著通常不需要顯式分配輸出數組。也就是說,可以不寫成:
Mat color;
...
Mat gray(color.rows, color.cols,color.depth());
cvtColor(color, gray, CV_BGR2GRAY);
而寫成:
Mat color;
...
Mat gray;
cvtColor(color, gray, CV_BGR2GRAY);
因為 cvtColor,與大多數 OpenCV 函數相同,在輸出數組時內部調用Mat::create()。
Mat::addref
計數器參考。
C++: void Mat::addref()
該方法遞增與矩陣數據關聯的引用計數。如果矩陣頭指向外部的數據集(見 Mat::Mat()),則引用計數為 NULL,并且該方法在這種情況下不起作用。通常情況下,為避免內存泄漏,不應顯式調用該方法。它是由該矩陣賦值運算符隱式調用。在支持的它平臺上,引用計數器遞增是一個原子操作。因此,對相同的矩陣,在不同的線程異步操作是安全的。
Mat::release
在必要的情況下,遞減引用計數并釋放該矩陣。
C++: void Mat::release()
該方法遞減與矩陣的數據關聯的引用計數。當引用計數減為0時,矩陣的數據將被釋放,數據和引用計數器指針設置為 NULL。如果矩陣頭指向外部數據集 (見 Mat::Mat()), 引用計數為 NULL,并且該方法在這種情況下無效。
可以手動調用此方法強制矩陣數據釋放。但由于這種方法在析構函數中是自動調用的,或以更改數據指針的其他方法,因此通常不需要調用這個函數。在支持它的平臺上,引用計數器遞減并檢查是否為0 是一個原子操作。因此,在不同的線程異步調用相同的矩陣是安全的操作。
Mat::resize
更改矩陣的行數。
C++: void Mat::resize(size_t sz)
C++: void Mat::resize(size_t sz, const Scalar& s)
參數
sz?–新的行數。
s?–分配給新添加的元素的值。
該方法更改矩陣的行數。如果矩陣重新分配,第一最少(Mat::rows,sz) 行數要保留下來。該方法模擬相應的 STL 向量類的方法。
Mat::reserve
保留一定數量的行的空間。
C++: void Mat::reserve(size_t sz)
參數
sz?–的行數。
該方法sz行存儲空間。如果矩陣已經有足夠的空間來存儲sz行,沒有任何異常發生。如果矩陣重新分配,保留前(Mat::rows) 行。該方法模擬了相應的STL 向量類的方法。
Mat::push_back
將元素添加到矩陣的底部。
C++: template<typename T> voidMat::push_back(const T& elem)
C++: void Mat::push_back(const Mat& elem)
參數
elem?–增加的一個或多個元素。
該方法將一個或多個元素添加到矩陣的底部。他們是模擬相應的 STL 向量類的方法。元素為Mat時,其類型和列的數目必須和矩陣容器是相同的。
Mat::pop_back
從底部的列表中刪除元素。
C++: template<typename T> voidMat::pop_back(size_t nelems=1)
參數
nelems?–刪除的行的數目。如果它大于總的行數,則會引發異常。
該方法從底部的列表中刪除一行或多行。
Mat::locateROI
父矩陣內定位矩陣頭。
C++: void Mat::locateROI(Size& wholeSize,Point& ofs) const
參數
wholeSize–輸出參數,其中包含的整個矩陣包含大小 * 這是其中一部分。
ofs?–輸出參數包含*this在整個的矩陣里面的偏移量。你使用Mat::row()、 Mat::col()、 Mat::rowRange()、Mat::colRange()以及其他的方法從矩陣中提取子陣后該結果子陣只指向原始大矩陣的一部分。然而,每個子陣包含有助于重建的最初矩陣大小和提取子陣在原始矩陣中的位置信息(由?datastart?和?dataend ?elds表示)。locateROI方法正是這樣做的。
Mat::adjustROI
調整子陣大小及其在父矩陣中的位置。
C++: Mat& Mat::adjustROI(int dtop, int dbottom,int dleft, int dright)
參數
dtop?–頂部子陣邊界向上的平移量。
dbottom?–底部子陣邊界向下的平移量。
dleft?–左子陣邊界向左的平移量。
dright?–右子陣邊界向右的平移量。
該方法是 Mat::locateROI() 的互補性方法。這些函數的典型應用是確定父矩陣中子陣的位置,然后以某種方式改變位置。尤其典型的是,當濾鏡操作中要考慮ROI外的像素時就需要它。當方法的所有參數都是正的時候,ROI需要以指定量全方位增長,例如:
A.adjustROI(2, 2, 2,2);
在此示例中,每個方向 4 元素增加矩陣大小。矩陣向左側和上側分別平移2 個元素,這會產生5 x 5 內核的濾鏡所需的所有像素。你的責任是確保 adjustROI 不超出父矩陣邊界。如果超出,該函數發出錯誤提示。OpenCV的濾鏡函數在內部調用該函數,像filter2D(),形態學的操作,等等。
另請參閱:
copyMakeBorder()
Mat::operator()
提取矩形子陣。
C++: Mat Mat::operator()(Range rowRange, RangecolRange) const
C++: Mat Mat::operator()(const Rect& roi) const
C++: Mat Mat::operator()(const Ranges* ranges) const
參數:
rowRange?–提取的子陣的開始和結束的行。不包括的上限。若要選擇的所有行,請使用 Range::all()。
colRange?–提取的子陣的開始和結束的列。不包括的上限。若要選擇的所有列,請使用 Range::all()。
roi – 抽出子陣 speci?ed 作為一個矩形。
ranges – 選定范圍沿每個數組維度的數組。
該運算符為*this的子數組創建新的頭。他們是Mat::row()、 Mat::col()、 Mat::rowRange(),和Mat::colRange()最普遍的形式。例如,A(Range(0, 10),Range::all()) 是相當于A.rowRange(0, 10)。與上述所有操作相同,該操作運算符是復雜度為O(1)的操作,就是沒有矩陣數據將被復制。
Mat::operator CvMat
創建矩陣 CvMat 頭。
C++: Mat::operator CvMat() const
該運算符創建矩陣 CvMat 的頭,而不復制的基礎數據。引用計數未被考慮到此操作中。因此,您應該確保CvMat 頭在使用的時候不釋放原始矩陣。該運算符對于新舊OpenCV API混用是有用的,例如:
Mat img(Size(320, 240), CV_8UC3);
...
CvMat cvimg = img;
mycvOldFunc( &cvimg, ...);
其中 mycvOldFunc 是用于OpenCV 1.x 數據結構的函數。
Mat::operator IplImage
創建IplImage矩陣頭。
C++: Mat::operator IplImage() const
運算符創建矩陣 IplImage 頭,而不復制的基礎數據。您應該確保使用IplImage頭時不釋放原矩陣。與Mat::operatorCvMat類似,該運算符在OpenCV新舊API混用中很有用。
Mat::total
返回數組元素的總數。
C++: size_t Mat::total() const
該方法返回數組元素(如果該數組表示圖像的像素數)的數目。
Mat::isContinuous
返回矩陣是否連續。
C++: bool Mat::isContinuous() const
如果在每一行的結尾無間隙連續存儲矩陣的元素,該方法返回 true。否則,它將返回 false。很明顯,1 x 1 或 1xN 矩陣始終是連續的。使用 Mat::create() 創建矩陣是始終是連續的。但是,如果您提取的矩陣,使用 Mat::col()、 Mat::diag(),等等,或外部已分配的數據構造的矩陣頭的一部分,那么這種矩陣可能不再具有此屬性。連續性標記在Mat::flags域內用一個位存儲,構造矩陣頭時可以自動計算出來。因此,連續性檢查是非常快速的操作,雖然理論上可以做,如下所示:
/ / 等價的Mat::isContinuous() 的執行情況
boolmyCheckMatContinuity(const Mat& m)
{
//返回 (m.flags & Mat::CONTINUOUS_FLAG) != 0;
return m.rows ==1 || m.step == m.cols*m.elemSize();
}
很多的OpenCV 函數中使用該方法。關鍵在于按元素操作(如算術和邏輯運算、 數學函數、 alpha 融合、顏色空間轉換,以及其他) 不依賴于圖像的幾何形狀。因此,如果所有的輸入和輸出的陣列是連續的,該函數可以它們作為很長的單行的向量處理。下面的示例闡釋了如何實現 alpha 融合功能。
template<typename T>
void alphaBlendRGBA(const Mat& src1,const Mat& src2, Mat& dst)
{
const float alpha_scale =(float)std::numeric_limits<T>::max(),
inv_scale = 1.f/alpha_scale;
CV_Assert( src1.type() == src2.type()&&
src1.type() ==CV_MAKETYPE(DataType<T>::depth, 4) &&
src1.size() == src2.size());
Size size = src1.size();
dst.create(size, src1.type());
// 規定如下: 檢查陣列的連續性
//如果的確如此,陣列連續
// 把陣列看做一維的向量。
if( src1.isContinuous() &&src2.isContinuous() && dst.isContinuous() )
{
size.width *= size. height;
size.height = 1;
}
size.width *= 4;
for( int i = 0; i < size.height; i++ )
{// 當陣列連續,
// 外循環只執行一次
const T* ptr1 = src1.ptr<T>(i);
const T* ptr2 = src2.ptr<T>(i);
T* dptr = dst.ptr<T>(i);
for( int j = 0; j < size.width; j += 4 )
{
float alpha = ptr1[j+3]*inv_scale, beta =ptr2[j+3]*inv_scale;
dptr[j] =saturate_cast<T>(ptr1[j]*alpha + ptr2[j]*beta);
dptr[j+1] =saturate_cast<T>(ptr1[j+1]*alpha + ptr2[j+1]*beta);
dptr[j+2] =saturate_cast<T>(ptr1[j+2]*alpha + ptr2[j+2]*beta);
dptr[j+3] = saturate_cast<T>((1 -(1-alpha)*(1-beta))*alpha_scale);
}
}
}
這種方法,不僅很簡單,而且在簡單的元素的操作中可以提高10-20%性能,尤其在圖像很小且操作非常簡單的時候。
在此函數中另一個 OpenCV 語法,目標數組中Mat::create() 的調用會對沒有適當大小和類型的目標數組分配空間。雖然新分配的數組始終是連續的,但您仍需要檢查目標數組,因為 Mat::create()不是總會分配一個新的矩陣。
Mat::elemSize
返回矩陣元素大小 (以字節為單位)。
C++: size_t Mat::elemSize() const
該方法返回以字節為單位的矩陣元素大小。例如,如果矩陣類型是 CV_16SC3,該方法返回3*sizeof(short)或 6。
Mat::elemSize1
以字節為單位返回每個矩陣元素通道的大小。
C++: size_t Mat::elemSize1() const
該方法返回以字節為單位的矩陣元素通道大小,也就是忽略通道的數量。例如,
如果矩陣類型是 CV_16SC3,該方法返回 sizeof(short) 或 2。
Mat::type
返回一個矩陣元素的類型。
C++: int Mat::type() const
該方法返回一個矩陣的元素類型。這是兼容CvMat 類型系統,像 CV_16SC3標識符
或 16 位有符號的3 通道陣列,等等。
Mat::depth
返回一個矩陣元素的深度。
C++: int Mat::depth() const
該方法返回矩陣元素深度(每個單獨的通道類型)的標識符。例如,對于16位有符號的3通道數組,該方法返回CV_16S。矩陣類型的完整列表包含以下內容值:
??CV_8U-8 位無符號整數 (0…..255)
??CV_8S-8 位符號整數 (-128…..127)
??CV_16U-16 位無符號整數 (0……65535)
??CV_16S-16 位符號整數 (-32768…..32767)
??CV_32S-32 位符號整數 (-2147483648……2147483647)
??CV_32F-32 位浮點數 (-FLT_MAX ………FLT_MAX,INF,NAN)
??CV_64F-64 位浮點數(-DBL_MAX ……….DBL_MAX,INF,NAN)
Mat::channels
返回矩陣通道的數目。
C++: int Mat::channels() const
該方法返回矩陣通道的數目。
Mat::step1
返回矩陣歸一化邁出的一步。
C + +: size_t const Mat::step1()
該方法返回以矩陣的step除以Mat::elemSize1()。它對快速訪問任意矩陣元素很有用。
Mat::size
返回一個矩陣大小。
C++: Size Mat::size() const
該方法返回一個矩陣大小:Size(cols, rows)。矩陣超過 2 維時返回大小為(-1,-1)。
Mat::empty
如果數組有沒有 elemens,則返回 true。
C++: bool Mat::empty() const
如果 Mat::total() 是 0 或 Mat::data 為 NULL,則方法返回 true。因為pop_back() 和 resize()方法M.total()= = 0,并不意味著M.data = =NULL。
Mat::ptr
返回指定矩陣行的指針。
C++: uchar* Mat::ptr(int i=0)
C++: const uchar* Mat::ptr(int i=0) const
C++: template<typename _Tp> _Tp* Mat::ptr(inti=0)
C++: template<typename _Tp> const _Tp*Mat::ptr(int i=0) const
參數:
i?–一個基于0的行索引。
該方法返回uchar*,或指向由輸入指定矩陣行的指針。參看Mat::isContinuous()的中示例了解如何使用這些方法。
Mat::at
返回對指定數組元素的引用。
C++: template<typename T> T& Mat::at(int i)const
C++: template<typename T> const T&Mat::at(int i) const
C++: template<typename T> T& Mat::at(int i,int j)
C++: template<typename T> const T&Mat::at(int i, int j) const
C++: template<typename T> T& Mat::at(Pointpt)
C++: template<typename T> const T&Mat::at(Point pt) const
C++: template<typename T> T& Mat::at(int i,int j, int k)
C++: template<typename T> const T&Mat::at(int i, int j, int k) const
C++: template<typename T> T& Mat::at(constint* idx)
C++: template<typename T> const T&Mat::at(const int* idx) const
參數
i?–索引 0 維度
j?– 1 維度的索引
k?– 沿 2 維度的索引
pt?– Point(j,i) 作為指定元素的位置。
idx?– Mat::dims 數組的索引。
該模板方法返回指定數組元素的引用。為了具有更高的性能,索引范圍檢查只在調試配置下執行。請注意使用具有單個索引 (i) 的變量可以訪問的單行或單列的2 維的數組元素。也就是比方說,如果A是1 x N 浮點矩陣和B是M x 1的整數矩陣,您只需編寫A.at<float>(k+4) 和 B.at<int>(2*i+1) 分別代替A.at<float>(0,k+4)和
B.at<int>(2*i+1,0)。
下面的示例將初始化希爾伯特矩陣:
Mat H(100,?100, CV_64F);
for(inti=?0; i<H.rows; i++)
for(intj=?0; j<H.cols; j++)
H.at<double>(i,j)=1./(i+j+1);
Mat::begin
返回矩陣迭代器,并將其設置為第一矩陣元。
C++: template<typename _Tp>MatIterator_<_Tp> Mat::begin()
C++: template<typename _Tp>MatConstIterator_<_Tp> Mat::begin() const
該方法返回矩陣的只讀或讀寫的迭代器。矩陣迭代器的使用和雙向 STL 迭代器的使用是非常相似的。在下面的示例中,alpha融合函數是使用矩陣迭代器重寫:
template<typename T>
void alphaBlendRGBA(const Mat& src1,const Mat& src2, Mat& dst)
{
typedef Vec<T, 4> VT;
const float alpha_scale =(float)std::numeric_limits<T>::max(),
inv_scale = 1.f/alpha_scale;
CV_Assert( src1.type() == src2.type()&&
src1.type() == DataType<VT>::type&&
src1.size() == src2.size());
Size size = src1.size();
dst.create(size, src1.type());
MatConstIterator_<VT> it1 =src1.begin<VT>(), it1_end = src1.end<VT>();
MatConstIterator_<VT> it2 =src2.begin<VT>();
MatIterator_<VT> dst_it =dst.begin<VT>();
for( ; it1 != it1_end; ++it1, ++it2,++dst_it )
{
VT pix1 = *it1, pix2 = *it2;
float alpha = pix1[3]*inv_scale, beta =pix2[3]*inv_scale;
*dst_it =VT(saturate_cast<T>(pix1[0]*alpha + pix2[0]*beta),
saturate_cast<T>(pix1[1]*alpha + pix2[1]*beta),
saturate_cast<T>(pix1[2]*alpha +pix2[2]*beta),
saturate_cast<T>((1 -(1-alpha)*(1-beta))*alpha_scale));
}
}
Mat::end
返回矩陣迭代器,并將其設置為 最后元素之后(after-last)的矩陣元。
C++: template<typename _Tp>MatIterator_<_Tp> Mat::end()
C++: template<typename _Tp>MatConstIterator_<_Tp> Mat::end() const
該方法返回矩陣只讀或讀寫的迭代器,設置為緊隨最后一個矩陣元素的點。
參考文檔:
1) http://blog.csdn.net/xiahouzuoxin/article/details/38298165
2)? http://www.cnblogs.com/wangguchangqing/p/4016179.html
總結
以上是生活随笔為你收集整理的OpenCV Mat 简介的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: IplImage简介
- 下一篇: OpenCV 3.0又一个革命性版本,它