Mat是OpenCV最基本的數(shù)據(jù)結(jié)構(gòu),Mat即矩陣(Matrix)的縮寫,Mat數(shù)據(jù)結(jié)構(gòu)主要包含2部分:Header和Pointer。Header中主要包含矩陣的大小,存儲方式,存儲地址等信息;Pointer中存儲指向像素值的指針。我們在讀取圖片的時候就是將圖片定義為Mat類型,其重載的構(gòu)造函數(shù)一大堆,
class CV_EXPORTS Mat
{
public:
//! default constructor
Mat();
//! 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 matrix
Mat(int _ndims, const int* _sizes, int _type);
Mat(int _ndims, const int* _sizes, int _type, const Scalar& _s);
//! copy constructor
Mat(const Mat& m);
//! constructor for matrix headers pointing to user-allocated data
Mat(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 matrix
Mat(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 default
Mat(const CvMat* m, bool copyData=false);
//! converts old-style CvMatND to the new matrix; the data is not copied by default
Mat(const CvMatND* m, bool copyData=false);
//! converts old-style IplImage to the new matrix; the data is not copied by default
Mat(const IplImage* img, bool copyData=false);
......
}
要了解如何初始化Mat結(jié)構(gòu),就應(yīng)該了解它的構(gòu)造函數(shù),比如程序中的第一初始化方式調(diào)用額就是
Mat(int _rows, int _cols, int _type, const Scalar& _s);
這個構(gòu)造函數(shù)。
IplImage*是C語言操作OpenCV的數(shù)據(jù)結(jié)構(gòu),在當(dāng)時C操縱OpenCV的時候,地位等同于Mat,OpenCV為其提供了一個接口,很方便的直接將IplImage轉(zhuǎn)化為Mat,即使用構(gòu)造函數(shù)
Mat(const IplImage* img, bool copyData=false);
上面程序中的第二種方法就是使用的這個構(gòu)造函數(shù)。
關(guān)于Mat數(shù)據(jù)復(fù)制:前面說過Mat包括頭和數(shù)據(jù)指針,當(dāng)使用Mat的構(gòu)造函數(shù)初始化的時候,會將頭和數(shù)據(jù)指針復(fù)制(注意:只是指針復(fù)制,指針指向的地址不會復(fù)制),若要將數(shù)據(jù)也復(fù)制,則必須使用copyTo或clone函數(shù)
Mat還有幾個常用的成員函數(shù),在之后的文章中將會使用到:
//! 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;
這了解上面的函數(shù)作用前,得了解下OpenCV中存儲像素的方法,如下,灰度圖(單通道)存儲按行列存儲,
三通道RGB存儲方式如下,每列含有三個通道,
為了加快訪問的速度,openCV往往會在內(nèi)存中將像素數(shù)據(jù)連續(xù)地存儲成一行,isContinus()函數(shù)的作用就是用于判斷是否連續(xù)存儲成一行。存儲成一行有什么好處呢?給定這行的頭指針p,則只要使用p++操作就能逐個訪問數(shù)據(jù)。
因此當(dāng)判斷存放在一行的時候,可以通過數(shù)據(jù)指針++很容易遍歷圖像像素:
long nRows = M.rows * M.channels(); // channels()也是Mat中一個常用的函數(shù),用于獲取通道數(shù)(RGB=3,灰度=1)
long nCols = M.cols;
uchar *p = M.data; // 數(shù)據(jù)指針
if(M.isContinuous())
{
nCols *= nRows;
for (long i=0; i < nCols; i++) {
*p++ = ...; // 像素賦值或讀取操作
}
}
請注意以上幾個常用的Mat成員遍歷和函數(shù):
M.row; // 返回圖像行數(shù)
M.nCols; // 返回圖像列數(shù)
M.channels(); //返回通道數(shù)
M.isContinuous(); // 返回bool類型表示是否連續(xù)存儲
更多關(guān)于Mat的信息請參考安裝目錄下的include/opencv2/core.hpp文件
左邊是矩陣的一些操作輸出結(jié)果,右邊的圖是通過IplImage *結(jié)構(gòu)讀入,轉(zhuǎn)換為Mat后顯示結(jié)果。