本文的內容來自兩篇博客文章,基本數據類型及介紹來自:
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