在Mat类中有两个成员函数:elemSize()和elemSize1(),来看看它们的作用及实现方式。
inline size_t Mat::elemSize() const { return dims > 0 ? step.p[dims-1] : 0; }
inline size_t Mat::elemSize1() const { return CV_ELEM_SIZE1(flags); }
先看第二个 函数elemSize1(),该函数的作用是计算depth所占的字节数(与通道数无关)。可参考对应的内置类型 Mat中的depth与对应的内置类型。根据其函数体可看出它其实是通过宏CV_ELEM_SIZE1()来工作的,来看看这个宏的细节:
/* Size of each channel item,
0x124489 = 1000 0100 0100 0010 0010 0001 0001 ~ array of sizeof(arr_type_elem) */ // 0x124489-->0x8442211
#define CV_ELEM_SIZE1(type) ((((sizeof(size_t)<<28)|0x8442211) >> CV_MAT_DEPTH(type)*4) & 15)
首先说明一下个人觉得在注释中的0x124489应该是有问题的,貌似该改成0x8442211。接下来分析实现过程。
size_t是为了增强程序的可移植性,在我64位的系统上,如果编译32位程序的则sizeof(size_t)等于4,若编译64位程序的则sizeof(size_t)等于8,这里以8为例:
如图
对于宏CV_MAT_DEPTH(type),可以参考从Mat的flags中可以读到的信息,以及相关宏定义,取type=CV_8UC3为例。
则CV_MAT_DEPTH(CV_8UC3)等于0,过程如下图:
最后的结果为1,我们知道CV_8UC3对应的的depth是CV_8U,占8位,故字节数为1,这与计算结果是相吻合的。
对于宏CV_ELEM_SIZE1(type)的理解,重点还是掌握((sizeof(size_t)<<28)|0x8442211)的规律性,它与相应的depth是一一对应的。
接下来看函数elemSize(),其作用是计算Mat中单个像素点所占的字节数(与通道数有关)。根据其函数体来看,它是通过Mat的两个成员变量dim和step来实现,但实际上在Mat实例化对应时elemSize()也是通过宏来实现的,该宏为:
/* 0x3a50 = 11 10 10 01 01 00 00 ~ array of log2(sizeof(arr_type_elem)) */
#define CV_ELEM_SIZE(type) (CV_MAT_CN(type) << ((((sizeof(size_t)/4+1)*16384|0x3a50) >> CV_MAT_DEPTH(type)*2) & 3))
在此就不一步一步的分析了,主要说明一下0x3a50的作用:
0x3a50 = 11 10 10 01 01 00 00,对照上图的最后一行即可看出它的含义。
CV_ELEM_SIZE(type)=CV_MAT_CN(type)*CV_ELEM_SIZE1(type)=CV_MAT_CN(type)<<log2(CV_ELEM_SIZE1(type))。
即:Mat.elemSize() = Mat.elemSize1() * Mat.channels()。
特别注意当depth为CV_USRTYPE1的情形。
要过年了,祝大家合家欢乐!