在Mat中flags的定义如下:
/*! includes several bit-fields:
- the magic signature
- continuity flag
- depth
- number of channels
*/
int flags;
从其描述可以看到,flags是一个int型变量,占4字节内存,共32位,我们把最高位称为第32位,最低位称为第1位,存储的内容可以用来表示当前Mat类对象的depth、channels、magic signature以及continuity等信息,那具体是如何通过flags来获取这些信息呢?下面一一来看。首先看到的是如何获取depth。depth在Mat的定义中有如下7种:
#define CV_8U 0
#define CV_8S 1
#define CV_16U 2
#define CV_16S 3
#define CV_32S 4
#define CV_32F 5
#define CV_64F 6
7种的话用二进制表示只用3个bit就可以表示了。在opencv中,depth不是一个成员变量,而获取depth的方法是通过以下函数:
inline int Mat::depth() const { return CV_MAT_DEPTH(flags); }
而其中CV_MAT_DEPTH(flags)是一个宏定义,其定义如下:
#define CV_MAT_DEPTH(flags) ((flags) & CV_MAT_DEPTH_MASK)
而其中CV_MAT_DEPTH_MASK也是一个宏定义,其定义如下:
#define CV_MAT_DEPTH_MASK (CV_DEPTH_MAX - 1)
而其中CV_DEPTH_MAX 还是一个宏定义,其定义如下:
#define CV_DEPTH_MAX (1 << CV_CN_SHIFT)
而其中CV_CN_SHIFT依然是一个宏定义,其定义如下:
#define CV_CN_SHIFT 3
吖的终于到底了。。这下就比较明朗了,3是一个字面值常量,在C++中是将其视为一个int型。那么CV_DEPTH_MAX 就是1 << 3,1也是一个字面值常量,有四个字节的空间,1的二进制表示为0000 0000 0000 0000 0000 0000 0000 0001,在左移3位之后,CV_DEPTH_MAX 的二进制表示为0000 0000 0000 0000 0000 0000 0000 1000,接着可以知道CV_MAT_DEPTH_MASK的值为0000 0000 0000 0000 0000 0000 0000 0111,最后可以知道获取depth即计算 (flags) & CV_MAT_DEPTH_MASK)的值,由于CV_MAT_DEPTH_MASK的最后三位为1,前面皆为0,所以最后flags与其相与的结果取等于前面29位都为0,后面三位是flags的最后三位,而这三位就可以表示Mat的7种depth了。因此得出结论:flags的第1位到第3位总共3bit表示depth。
然后再来看看如何flags是如何表示channels的信息的。和depth一样,channels也不是Mat的一个成员变量,获取channels的唯一方法是通过以下函数:
inline int Mat::channels() const { return CV_MAT_CN(flags); }
而CV_MAT_CN(flags)是一个宏定义,其定义如下:
#define CV_MAT_CN(flags) ((((flags) & CV_MAT_CN_MASK) >> CV_CN_SHIFT) + 1)
而CV_MAT_CN_MASK和CV_CN_SHIFT都是宏定义,其各自的定义如下:
#define CV_MAT_CN_MASK ((CV_CN_MAX - 1) << CV_CN_SHIFT)
#define CV_CN_SHIFT 3
而CV_CN_MAX 还是一个宏定义,其定义如下:
#define CV_CN_MAX 512
终于又到底了。。因为CV_CN_MAX是512,那么CV_MAT_CN_MASK是0000 0000 0000 0000 1111 1111 1000,那么channels就等于((((flags) & 0000 0000 0000 0000 1111 1111 1000) >> CV_CN_SHIFT) + 1),可以看到,最后的channels的 结果取决于flags的第4位到12位总共9bit表示channels,在Mat中channels的最大值为512,这个时候flags中的第4位到第12位为1111 1111 1。
depth和channels信息共同构成了type信息,获取type的函数及其相关的宏定义如下:
inline int Mat::type() const { return CV_MAT_TYPE(flags); }
#define CV_MAT_TYPE(flags) ((flags) & CV_MAT_TYPE_MASK)
#define CV_MAT_TYPE_MASK (CV_DEPTH_MAX*CV_CN_MAX - 1)
#define CV_DEPTH_MAX (1 << CV_CN_SHIFT)
#define CV_CN_SHIFT 3
#define CV_CN_MAX 512
然后再来看看continuity这个信息,这个信息表示的是Mat的数组在内存中是否是连续存储的,它也不是以一个成员变量的形式表示,要想获取这个信息,必须通过以下函数:
bool isContinuous() const;
其定义如下:
inline bool Mat::isContinuous() const { return (flags & CONTINUOUS_FLAG) != 0; }
而CONTINUOUS_FLAG是一个宏定义,其定义以如下:
CONTINUOUS_FLAG=CV_MAT_CONT_FLAG
CV_MAT_CONT_FLAG也是一个宏定义,其定义如下:
#define CV_MAT_CONT_FLAG (1 << CV_MAT_CONT_FLAG_SHIFT)
而CV_MAT_CONT_FLAG_SHIFT 也是一个宏定义,其定义如下:
#define CV_MAT_CONT_FLAG_SHIFT 14
然后开始反推回去,CV_MAT_CONT_FLAG等于0000 0000 0000 0000 0100 0000 0000 0000,所以CONTINUOUS_FLAG也等于0000 0000 0000 0000 0100 0000 0000 0000,最后isContinuous函数返回flags & 0000 0000 0000 0000 0100 0000 0000 0000) != 0,这是一个bool值,只有当flags的第15位是1时,返回true,如果flags的第15位是0时,返回false。因此得出结论:flags的第15位用来表示Mat在内存中的存储是否连续,且当其为1时表示连续存储,为0时表示不连续存储。
这个flags还可以用于表示当前的Mat是否是另一个Mat的submatrix。用以下函数可以知道当前的Mat是否是另一个Mat的submatrix,其定义如下:
inline bool Mat::isSubmatrix() const { return (flags & SUBMATRIX_FLAG) != 0; }
而SUBMATRIX_FLAG是一个宏定义,其定义如下:
SUBMATRIX_FLAG=CV_SUBMAT_FLAG
而CV_SUBMAT_FLAG也是一个宏定义,其定义如下:
#define CV_SUBMAT_FLAG (1 << CV_SUBMAT_FLAG_SHIFT)
CV_SUBMAT_FLAG_SHIFT也是一个宏定义,其定义如下:
#define CV_SUBMAT_FLAG_SHIFT 15
现在开始反推回去,CV_SUBMAT_FLAG等于0000 0000 0000 0000 1000 0000 0000 0000,所以 SUBMATRIX_FLAG也等于0000 0000 0000 0000 1000 0000 0000 0000,所以isSubmatrix函数返回flags & SUBMATRIX_FLAG) != 0,这是一个bool值,只有当flags的第16位是1时,返回true,为0时返回false。所以得出结论:flags的第16位用来表示当前矩阵是否是另一个矩阵的submatrix,如果该位是1则表示是,是0则表示不是。
17到32位表示的是magic signature的信息,这个的用处我还没有看到,网上也有博客说是用来区分Mat的类型,如果Mat和SparseMat的,后面有看到它的用处再把这部分加上去吧。
小结:
从低位到高位:
1-3位代表depth即数据类型(如CV_8U),OpenCV的数据类型共7类,故只需3位即可全部表示。
4-12位代表通道数channels,因为opencv默认最大通道数为512,故只需要9位即可全部表示,可参照下面求通道数的部分。
1-12位共同代表type即通道数和数据类型(如CV_8UC3)
13-14位暂没发现用处,也许是留着后用,待发现了再补上。
15位代表Mat的内存是否连续,一般由creat创建的mat均是连续的,如果是连续,将加快对数据的访问。
16位代表该Mat是否为某一个Mat的submatrix,一般通过ROI以及row()、col()、rowRange()、colRange()等得到的mat均为submatrix。
17-32代表magic signature,暂理解为用来区分Mat的类型。
本博客部分内容来自http://blog.csdn.net/yiyuehuan/article/details/43701797