上一节我们介绍了利用imread函数读取图像信息到一个Mat类中,
那么图像数据时如何在Mat中存储的呢?
Class Mat
class CV_EXPORTS Mat { public: // ... a lot of methods ... ... /*! includes several bit-fields: - the magic signature - continuity flag - depth - number of channels */ int flags; //! the array dimensionality, >= 2 int dims; //! the number of rows and columns or (-1, -1) when the array has more than 2 dimensions int rows, cols; //! pointer to the data uchar* data; //! pointer to the reference counter; // when array points to user-allocated data, the pointer is NULL int* refcount; // other members ... };
Mat初解
Mat是包含两个数据部分的基本类:
1. 矩阵头文件。
包含矩阵大小(rows,cols)、矩阵维数(dims)等等。
分别用成员变量rows、cols、dims保存。
2. 指向存储像素值的矩阵的指针(data)。
成员变量data给出了像素矩阵存储的初始位置,如今矩阵的大小,矩阵维数已知,想确定像素矩阵的内存位置,
我们还需要知道像素数据的类型,因为不同数据类型占用内存大小可能不相同。
常见类型有:
enum { CV_8U=0, CV_8S=1, CV_16U=2, CV_16S=3, CV_32S=4, CV_32F=5, CV_64F=6 };
\\ 8-bit unsigned integer (uchar)
\\ 8-bit signed integer (schar)
\\ 16-bit unsigned integer (ushort)
\\ 16-bit signed integer (short)
\\ 32-bit signed integer (int)
\\ 32-bit floating-point number (float)
\\ 64-bit floating-point number (double)
以上类型,我们在Mat的数据结构中,常称之为depth。
彩色图像的存在,Mat同样支持多通道数据。CV_8U_C1,CV_8U_C2,CV_8U_C3,...,CV_64F_C4,对应于通道1-4。
当然,还可以有更多的通道,通过宏CV_MAKETYPE(depth, n) == ((depth&7)<<3) + (n-1)定义。
常用的Mat成员变量及函数
成员变量:
int dims,//矩阵维数
int rows,//矩阵行数
int cols,//矩阵列数,不考虑通道影响,亦即若是rgb彩色图像,一列中包含了rgb三个通道的数据
uchar *data,//像素矩阵的起始位置
Mstep step,//step[i]描述了在维度i中相邻元素的内存距离
//对于一个2维矩阵:维度0,行;维度1,列
//注意到step[i] >= step[i+1]*size[i+1],这也意味着
//二维矩阵按行存储,三维矩阵按面存储,
//step[dims-1] = elemSize()。
成员函数:
OpenCV2的Mat类中定义了很多类似Matlab矩阵操作的成员函数,比如
+,-,*,等运算符的重定义;
Mat row(int y),Mat col(int x),Mat rowRange(int startrow, int endrow) const,Mat rowRange(const Range& r) const,Mat colRange(int startrow, int endrow) const,Mat colRange(const Range& r) const,等行列操作;
MatExpr t() const //转置,MatExpr inv(int method=DECOMP_LU) const//求逆,等等矩阵运算;
图像相关函数,
bool isContinuous() const //像素矩阵在内存中是否是连续的,size_t elemSize() const //像素矩阵单个数据的字节数,此时单个数据以列为单位,不计通道数,如RGB三通道数据视为一个单元//所以CV_16SC3数据类型矩阵的返回值为3*sizeof(short) = 6size_t elemSize1() const //像素矩阵单个数据的字节数,此时单个数据以列为单位,计通道数,如RGB三通道数据视为三个单元//所以CV_16SC3数据类型矩阵的返回值为sizeof(short) = 2int type() const //返回矩阵的数据类型,int depth() const //返回矩阵的深度,即去掉通道数的类型,int channels() const //返回矩阵的通道数,uchar* ptr(int i0=0),const uchar* ptr(int i0=0) const,template<typename _Tp> _Tp* ptr(int i0=0),template<typename _Tp> const _Tp* ptr(int i0=0) const//返回i0行的首地址 。
图像像素矩阵在内存中的存储方式
我们已经知道用函数imread读取的图像像素值存储在data所指向的内存中,
那么该数据在内存中如何存储的呢?
单通道图像,如灰度图像,存储方式如下
多通道图像,每列数据包含通道个数的子列,如采用RGB色彩,存储方式如下
值得注意的是,数据存储顺序是BGR,与RGB顺序相反。
从上述两图,还可以发现:Mat中cols的概念并不是简单的矩阵列数,应该考虑上channels的影响。
存储矩阵的列数应为cols*nchannels。
对于一个二维的图像矩阵M,其坐标为(i,j)数据的内存地址为addr(M_{i,j}) = M.data + i*M.step[0] + j*M.step[1]。
参考文献
- The OpenCV Reference Manual Release 2.4.9.0。
- The OpenCV Tutorials Release 2.4.9.0。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用。你还可以使用@来通知其他用户。