小小研究了一下CvMat里面的宏,发现设计人员对位运算的使用 "别具匠心",值得我们学习!
研究结果:
/****************************************************************************************\ * Matrix type (CvMat) * \****************************************************************************************/ #define CV_CN_MAX 512 #define CV_CN_SHIFT 3 #define CV_DEPTH_MAX (1 << CV_CN_SHIFT) #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 #define CV_USRTYPE1 7 #define CV_MAT_DEPTH_MASK (CV_DEPTH_MAX - 1) #define CV_MAT_DEPTH(flags) ((flags) & CV_MAT_DEPTH_MASK) #define CV_MAKETYPE(depth,cn) (CV_MAT_DEPTH(depth) + (((cn)-1) << CV_CN_SHIFT)) #define CV_MAKE_TYPE CV_MAKETYPE #define CV_8UC1 CV_MAKETYPE(CV_8U,1) #define CV_8UC2 CV_MAKETYPE(CV_8U,2) #define CV_8UC3 CV_MAKETYPE(CV_8U,3) #define CV_8UC4 CV_MAKETYPE(CV_8U,4) #define CV_8UC(n) CV_MAKETYPE(CV_8U,(n)) #define CV_8SC1 CV_MAKETYPE(CV_8S,1) #define CV_8SC2 CV_MAKETYPE(CV_8S,2) #define CV_8SC3 CV_MAKETYPE(CV_8S,3) #define CV_8SC4 CV_MAKETYPE(CV_8S,4) #define CV_8SC(n) CV_MAKETYPE(CV_8S,(n)) #define CV_16UC1 CV_MAKETYPE(CV_16U,1) #define CV_16UC2 CV_MAKETYPE(CV_16U,2) #define CV_16UC3 CV_MAKETYPE(CV_16U,3) #define CV_16UC4 CV_MAKETYPE(CV_16U,4) #define CV_16UC(n) CV_MAKETYPE(CV_16U,(n)) #define CV_16SC1 CV_MAKETYPE(CV_16S,1) #define CV_16SC2 CV_MAKETYPE(CV_16S,2) #define CV_16SC3 CV_MAKETYPE(CV_16S,3) #define CV_16SC4 CV_MAKETYPE(CV_16S,4) #define CV_16SC(n) CV_MAKETYPE(CV_16S,(n)) #define CV_32SC1 CV_MAKETYPE(CV_32S,1) #define CV_32SC2 CV_MAKETYPE(CV_32S,2) #define CV_32SC3 CV_MAKETYPE(CV_32S,3) #define CV_32SC4 CV_MAKETYPE(CV_32S,4) #define CV_32SC(n) CV_MAKETYPE(CV_32S,(n)) #define CV_32FC1 CV_MAKETYPE(CV_32F,1) #define CV_32FC2 CV_MAKETYPE(CV_32F,2) #define CV_32FC3 CV_MAKETYPE(CV_32F,3) #define CV_32FC4 CV_MAKETYPE(CV_32F,4) #define CV_32FC(n) CV_MAKETYPE(CV_32F,(n)) #define CV_64FC1 CV_MAKETYPE(CV_64F,1) #define CV_64FC2 CV_MAKETYPE(CV_64F,2) #define CV_64FC3 CV_MAKETYPE(CV_64F,3) #define CV_64FC4 CV_MAKETYPE(CV_64F,4) #define CV_64FC(n) CV_MAKETYPE(CV_64F,(n)) #define CV_AUTO_STEP 0x7fffffff #define CV_WHOLE_ARR cvSlice( 0, 0x3fffffff ) #define CV_MAT_CN_MASK ((CV_CN_MAX - 1) << CV_CN_SHIFT) #define CV_MAT_CN(flags) ((((flags) & CV_MAT_CN_MASK) >> CV_CN_SHIFT) + 1) #define CV_MAT_TYPE_MASK (CV_DEPTH_MAX*CV_CN_MAX - 1) #define CV_MAT_TYPE(flags) ((flags) & CV_MAT_TYPE_MASK) #define CV_MAT_CONT_FLAG_SHIFT 14 #define CV_MAT_CONT_FLAG (1 << CV_MAT_CONT_FLAG_SHIFT) #define CV_IS_MAT_CONT(flags) ((flags) & CV_MAT_CONT_FLAG) #define CV_IS_CONT_MAT CV_IS_MAT_CONT #define CV_SUBMAT_FLAG_SHIFT 15 #define CV_SUBMAT_FLAG (1 << CV_SUBMAT_FLAG_SHIFT) #define CV_IS_SUBMAT(flags) ((flags) & CV_MAT_SUBMAT_FLAG) #define CV_MAGIC_MASK 0xFFFF0000 #define CV_MAT_MAGIC_VAL 0x42420000 #define CV_TYPE_NAME_MAT "opencv-matrix" /************** 我的研究结果 *****************/ /*** 宏嵌套 ***/ #define C A #define A B #define B 1 /*** A=B=C=1 ***/ #define CV_CN_MAX 512 //最大通道 #define CV_CN_SHIFT 3 //偏移 #define CV_DEPTH_MAX 8 //最大深度8位(单个字节) //DEPTH的取值类型,占3位 #define CV_8U 0 //unsigned char #define CV_8S 1 //char #define CV_16U 2 //unsigned short #define CV_16S 3 //short #define CV_32S 4 //int #define CV_32F 5 //float #define CV_64F 6 //double #define CV_USRTYPE1 7 #define CV_MAT_DEPTH_MASK 7 // 0000 0000 0111 #define CV_MAT_DEPTH(flags) ((flags) & 7) /*** depth + cn 编码 ***/ //depth占低3位,cn-1占高位 #define CV_MAKETYPE(depth,cn) ((depth & 7) + ((cn - 1) << 3)) #define CV_MAKE_TYPE CV_MAKETYPE #define CV_MAT_CN_MASK 4088 // 1111 1111 1000 // (((flags) & CV_MAT_CN_MASK) >> CV_CN_SHIFT) ==> 0 <= flags < 4096时,等价于右移三位 // 后面可以发现 CV_MAT_CN_MASK = 1111 1111 1000, flags确实在这个范围里,所以其实也可以写成 ((flags) >> CV_CN_SHIFT) #define CV_MAT_CN(flags) ((((flags) & CV_MAT_CN_MASK) >> CV_CN_SHIFT) + 1) #define CV_MAT_TYPE_MASK 4095 // 1111 1111 1111 #define CV_MAT_TYPE(flags) ((flags) & 4095) /******************* 规律 *********************/ * TYPE_MASK = DEPTH_MASK | CN_MASK * * CV_MAT_TYPE_MASK 1111 1111 1111 * * CV_MAT_DEPTH_MASK 0000 0000 0111 * * CV_MAT_CN_MASK 1111 1111 1000 * /**********************************************/ #define CV_MAT_CONT_FLAG_SHIFT 14 #define CV_MAT_CONT_FLAG (1 << 14) //16384 #define CV_IS_MAT_CONT(flags) ((flags) & 16384) //二进制表示,右数第15位是否为1 #define CV_IS_CONT_MAT CV_IS_MAT_CONT #define CV_SUBMAT_FLAG_SHIFT 15 #define CV_SUBMAT_FLAG (1 << 15) //32768 #define CV_IS_SUBMAT(flags) ((flags) & 32768) //二进制表示,右数第16位是否为1 #define CV_MAGIC_MASK 0xFFFF0000 // 1111 1111 1111 1111 0000 0000 0000 0000 #define CV_MAT_MAGIC_VAL 0x42420000 // 0100 0010 0100 0010 0000 0000 0000 0000 // 0100 0010 0100 0010 0100 低12位由type决定 // 其中type低3位由DEPTH决定,高9位由(CN-1)<<3决定,显然CN最大为4088,即CV_MAT_CN_MASK cvMat.type = CV_MAT_MAGIC_VAL | CV_MAT_CONT_FLAG | type;
然后我们写一段程序来验证一下:
#include<iostream> #include<opencv2/opencv.hpp> using namespace std; int main() { int matrix[] = {1,2,3,4,5,6}; CvMat mat; cvInitMatHeader(&mat,2,3,CV_32SC1,matrix); int x = mat.type; cout<< x <<endl; //0100 0010 0100 0010 0100 0000 0000 0100 for(int i = 31,j = 0;i >= 0;i--){ if(j%4 == 0) putchar(' '); cout<<((x & 1<<i) > 0); j++; } return 0; }
由于CV_32SC1,是单通道,所以低12位的前9位为(1-1)<<3 = 0,这样CV_32SC1 = CV_32S = 4,所以对于单通道图像,其实type = depth,所以我们可以直接写 cvInitMatHeader(&mat,2,3,CV_32S,matrix); 效果是一样的,然后根据上面的分析:cvMat.type = CV_MAT_MAGIC_VAL | CV_MAT_CONT_FLAG | type;
所以前20位为0100 0010 0100 0010 0100,这样我们得到32位数0100 0010 0100 0010 0100 0000 0000 0100,最后我们取mat.type并将其转成二进制,可以发现输出的结果就是我们算出来的这32位,因此验证了我们上面的分析。
#include<iostream> #include<opencv2/opencv.hpp> using namespace std; int main() { int matrix[] = {1,2,3,4,5,6}; CvMat mat; cvInitMatHeader(&mat,1,3,CV_32SC2,matrix); //0100 0010 0100 0010 0100 0000 0000 1100 //取type cout<< cvGetElemType(&mat) <<endl; cout<< (mat.type & ((1 << 12) - 1))<<endl; cout<< (mat.type & CV_MAT_TYPE_MASK)<<endl; //取depth cout<< (mat.type & CV_MAT_DEPTH_MASK)<<endl; //取cn cout<< ((mat.type & CV_MAT_CN_MASK) >> 3) + 1<<endl; return 0; }
typedef struct CvMat { int type; int step; /* for internal use only */ int* refcount; int hdr_refcount; union { uchar* ptr; short* s; int* i; float* fl; double* db; } data; #ifdef __cplusplus union { int rows; int height; }; union { int cols; int width; }; #else int rows; int cols; #endif } CvMat;