本文的内容来自两篇博客文章,基本数据类型及介绍来自:
http://blog.csdn.net/kfqcome/article/details/8314175?reload
基本数据类型对应的空间大小和范围的知识来自:
http://www.rosoo.net/a/201106/14601.html
转载这两个内容主要是因为自己在实际使用中对图片进行灰度处理时,使用的方法是将一个三通道的图像矩阵转换成单通道的矩阵,三通道矩阵的数据类型是CV_8UC3,转换后单通道的类型是CV_32FC1(也就是float类型)。由于数据的范围不匹配导致出现意想不到的错误。原因是CV_8UC3的数据表示范围是0~255,而CV_32FC1的表示范围是0~1。
话不多说,直接上文章:
一基础
1 位移操作
移位操作有两种类型,一种是逻辑移位(logical shift)和算术移位(arithmetic shift)。逻辑移位中被移出的位被丢弃,空缺位(variant bit)用0填充。算术移位中移出位被丢弃,空缺位用符号位填充。
在c/c++中,整数分为有符号和无符号两种类型,它们的移位操作有所区别。对于无符号整数,左移右移均采用逻辑移位;对于有符号整数,右移使用算术移位,左移使用逻辑移位。
所以对于有符号整数的右移,并不会改变整数的正负,但是左移中却有可能会改变。
2 负数存储
在机器里,有符号的整数的存储,对于负整数来说,它是用补码存储的,这里需要知道原码,反码和补码。原码指的本来的数据,反码则是对原码按位取反,补码则是对原码取反后加1,即补码=反码+1
以占两个字节长度的数据为例,它的取值范围是-32768-32767。
1000 0000 0000 0000(原码) --->0111 1111 1111 1111(反码)-->1000 0000 0000 0000(补码)
该补码的值是32768,因为它本来是负值,所以1000 0000 0000 0000(原码)表示的值即为-32768
1111 1111 1111 1111(原码)--->0000 0000 0000 0000(反码)-->0000 0000 0000 0001(补码),所以这里原码表示的值是-1
二 opencv矩阵元素类型
1 CV_MAKETYPE
创建矩阵的时候,有几个函数,下面是其中的
CvMat cvMat(introws,intcols, inttype,void*dataCV_DEFAULT(NULL))
cvCreateMat( intheight,intwidth,int type )
从这些函数可以看出,第三个参数type用来确定矩阵的类型,它是int类型的,在当前的32位程序中,它占4个字节。矩阵元素类型包括了两部分信息,首先是元素数据的类型,还有就是该元素包含的通道个数。
opencv中矩阵的类型有如下几种:
#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_8UC1 CV_MAKETYPE(CV_8U,1)
#define CV_8UC2 CV_MAKETYPE(CV_8U,2)
....
#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_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_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_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_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_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_64FC(n)CV_MAKETYPE(CV_64F,(n))
这些数据类型都以宏的形式定义,它们的具体含义通过宏CV_MAKETYPE来确定,该宏包含两个参数,第一个参数指明数据的类型,第二个指明每个元素的通道数,每个元素至少需要有一个通道,直接使用CV_8U这样的类型表示的是一个通道。进一步查看它们的定义
#define CV_CN_MAX 512
#define CV_CN_SHIFT 3
#define CV_DEPTH_MAX (1 <<CV_CN_SHIFT) //值为1000(2进制)
#define CV_MAT_DEPTH_MASK (CV_DEPTH_MAX- 1) //值为0111
#define CV_MAT_DEPTH(flags) ((flags) &CV_MAT_DEPTH_MASK)//取flags的低3位
#define CV_MAKETYPE(depth,cn) (CV_MAT_DEPTH(depth)+ (((cn)-1) << CV_CN_SHIFT))
在CV_MAKETYPE的使用过程中,cn的取值可以是1到n,n一般不超过CV_CN_MAX。(((cn)-1) <<CV_CN_SHIFT)得到的结果是低三位必然0,只有高于低三位的位才有值,也就是说CV_MAKETYPE(depth,cn)得到的结果有两部分组成,第一部分是低3位的数据,这部分数据指明了数据的类型,第二部分则是高于低3位的其他位,这部分指明了矩阵元素的通道个数,这两部分互补干扰。
同时该宏生成的数据被传递给int类型的参数,由于该宏中只包含左移操作,所以无需考虑符号位的问题。
2 其他常用宏
l #define CV_MAT_CN_MASK ((CV_CN_MAX- 1) <<CV_CN_SHIFT)
0010 0000 0000 - 1 -->0001 1111 1111<< 3 -->1111 1111 1000
|#define CV_MAT_CN(flags) ((((flags) &CV_MAT_CN_MASK) >>CV_CN_SHIFT)+ 1)
这个操作是取出矩阵的通道个数,(flags) & CV_MAT_CN_MASK)首先是取出通道位,为什么可以使用CV_MAT_CN_MASK <--((CV_CN_MAX - 1)<<CV_CN_SHIFT)来取出通道位呢,从上面的矩阵类型的定义宏可以看出
#define CV_MAKETYPE(depth,cn) (CV_MAT_DEPTH(depth)+ (((cn)-1) << CV_CN_SHIFT))
这里面就是((cn)-1) << CV_CN_SHIFT)定义了通道位,而又因为cn的值不超过CV_CN_MAX,所以可以使用(flags) & ((CV_CN_MAX - 1) << CV_CN_SHIFT)来取出通道位。CV_MAT_CN就是CV_MAKETYPE里计算通道的逆操作。
l #define CV_MAT_TYPE_MASK (CV_DEPTH_MAX*CV_CN_MAX - 1)
值为8*512 -1 = 0001 0000 0000 0000 = 1111 1111 1111
可以用它来提取出表示矩阵类型的位,这里需要验证一下表示类型的数据的大小,也就是使用
max((cn-1)>> CV_CN_SHIFT) = (CV_CN_MAX-1)>> CV_CN_SHIFT= (0010 0000 0000-1)>>3 = (0001 1111 1111)>>3 = 1111 1111 1000
从这里可以看出,表示通道数的最大值如上,而表示数据类型的最大值为0111,所以表示矩阵元素类型的值的大小不超过11111111 1111,因而可以用掩码CV_MAT_TYPE_MASK提取出来
l #define CV_MAT_TYPE(flags) ((flags) &CV_MAT_TYPE_MASK)
使用取出表示矩阵元素类型的位,包括数据类型和通道数信息,也就是提取出使用CV_MAKETYPE(depth,cn)生成的数据
|#define CV_MAT_DEPTH(flags)
#define CV_CN_SHIFT 3
#define CV_DEPTH_MAX (1 <<CV_CN_SHIFT) //值为1000(2进制)
#define CV_MAT_DEPTH_MASK (CV_DEPTH_MAX- 1) //值为0111
#define CV_MAT_DEPTH(flags) ((flags) &CV_MAT_DEPTH_MASK)//取flags的低3位
即该宏取数据的低三位,这三位表示的是单个通道对应的数据类型,最大值为7,表示用户自定义类型。
。。。。。。
第二篇文章无法复制,直接点链接:http://www.rosoo.net/a/201106/14601.html