
1. 前言
本篇內容基于JAVA環境下,介紹OpenCV 4.6.0v 中創建 Mat 對象時傳遞的 CvType 參數。
如果你不太能理解CvType.CV_8UCX,CvType.CV_8SCX,CvType.CV_16UCX,CvType.CV_16SCX等
等參數的作用和意義。
那么,這篇文章 一文弄明白 OpenCV Mat 中通道channels的作用 可以幫你解惑。
以下內容基于OpenCV SDK 4.6.0v
2. CvType
這個類型主要是用來定義Mat中的數據類型的。常見使用場景就是在創建Mat的時候,進行定義。
那么CvType這個類型會定義哪些參數呢?很簡單它決定了Mat中的圖片數據的兩個基本指標:
通道channels:也就是mat.channels() 返回的值只能是1~4 這三個參數。 深度depth:也就是mat中每個像素參數的儲值范圍。該值存儲在每個通道中的byte[]數組中,每個數組中的數值的范圍就是由深度進行決定的。關于通道的概念,我前面有篇文章介紹過https://zinyan.com/?p=493。如果不太了解通道的概念可以閱讀上篇內容。
2.1 深度-depth我們通過CvType源碼可以看到,OpenCV已經定義好了8種深度參數:
public static final int CV_8U = 0, CV_8S = 1, CV_16U = 2, CV_16S = 3, CV_32S = 4, CV_32F = 5, CV_64F = 6, CV_16F = 7;上面名稱中的8U,8S,16U,16S,32S,64F,16F等等前面的數字代表了比特數
也就是說:8bite,16bite,32bite,64bite。用來定義取值范圍,后面的字母U,S,F代表了符號和精度。
U : unsigned int , 無符號整形,也就正整數 S : signed int , 有符號整形,包括負數和正數,但是都是整數 F : float , 單精度浮點型,也就是帶小數點。(PS:Float類型本身是支持負數的)所以結合定義我們就能理解:
CV_8U:是一個8位正整數,代表參數的取值范圍 0~255 CV_8S:是一個8位正負數,代表參數的取值范圍 -128~127 CV_16U:是一個16位正整數,代表參數的取值范圍 0~65535 CV_16S:是一個16位正負數,代表參數的取值范圍 -32768~32767 CV_16F:是一個16位浮點數,代表參數的取值范圍 -65504 ~ 65504 CV_32S:是一個32位正整數,代表參數的取值范圍 2147483648~2147483647 CV_32F:是一個32位浮點數,代表參數的取值范圍 1.18x10^-38^~3.40x10^38^ CV_64F:是一個64位浮點數,代表參數的取值范圍 2.23x10^-308^~1.79x10^308^PS:關于浮點數的精度問題和范圍問題,大家可以搜索更詳細的。上面的參數范圍通過網絡匯總得到的。
2.2 通道-channels在OpenCV定義中,通道數最大為4,最小為1.體現在代碼中,也就是CvType類中定義的C1,C2,C3,C4了。
C1:代表單通道 C2:代表雙通道 C3:代表三通到 C4:代表四通道在OpenCV中,一個像素點的顏色值采用duble[] 雙精度浮點數組存儲。
而通道就定義了這個double[] 數組的長度。
例如圖片是一個RGB格式的彩色圖片,那么圖片中的一個像素就需要R,G,B三個值混合才能確定具體顏色。
我們就需要一個double[3]的數組來記錄下分別記錄下該像素點下面的R,G,B的值分別是多少。
所以這張圖片采用的就是C3三通道。
而RGB通常是0~255范圍的整數。
OpenCV就通過我們上面介紹的深度來表示顏色的取值范圍。
兩者結合起來就是:
CvType.CV_8UC3 :表示三通道,每個通道內參數的取值范圍為8位正整數,也就是0~255
最后,我們結合Mat創建時的參數來理解就是:
//zinyan:創建了一個4*4尺寸的圖片。每個像素點存儲了一個double[1]的數組,該數組中值的范圍為0~255 Mat mat = new Mat(4, 4, CvType.CV_8UC1); //通常用來表示灰度圖或黑白圖 //zinyan:創建了一個5*5尺寸的圖片。每個像素點存儲了一個double[3]的數組,該數組中值的范圍為0~255 Mat mat1 = new Mat(5, 5, CvType.CV_8UC3); //通常用來表示彩色圖 //zinyan:創建了一個6*6尺寸的圖片。每個像素點存儲了一個double[3]的數組,該數組中值的范圍為0~65535 Mat mat1 = new Mat(6, 6, CvType.CV_16UC3); //通常用來表示彩色圖,顏色值范圍更廣。歸納一下,CvType定義的都是Mat中的數據存儲的類型。
定義了Mat存儲的像素值是由多少個,每個像素值的取值范圍是多少。
因為針對Mat的各種算法都是處理的每個像素點的數值。處理數值進行計算,就需要告訴算法每個數值的取值范圍是多少。
3. 其他
假如Mat是通過外部傳入過來的。我們如何確定Mat的通道數和每個數值的取值范圍呢?
CvType中提供了相關的查詢方法,可以讓我們通過type類型進行轉換為相應的類型值。
示例如下:
Mat mat = new Mat(4, 4, CvType.CV_8UC3); int depth = CvType.depth(mat.type()); //輸出結果值為 0 == CvType.CV_8U Mat mat1 = new Mat(4, 4, CvType.CV_16SC1); depth = CvType.depth(mat1.type()); //輸出結果值為 3 == CvType.CV_16S除此之外還可以進行通道數查詢。
Mat mat1 = new Mat(4, 4, CvType.CV_16SC1); int channels = CvType.channels(mat1.type()); //該值為1 3.1 廢棄 CV_USRTYPE1關于CvType.CV_USRTYPE1? 的值已經等同于CV_16F?了。所以該參數也被打上了@deprecated注解。代表已經被廢棄
建議大家不要使用。
3.2 ELEM_SIZE 方法CvType中的其他方法都比較好理解。最后就有一個public static final int ELEM_SIZE(int type) 方法
該方法傳遞type值。也就是所謂的CvType.CV_8UC1等參數值。
然后返回的是一個int變量。
該方法返回的變量是為了表示每個通道中的參數的字節數。1字節表示8bit,也就是8位。
所以我們如果是CV_8U,CV_8S,直接返回通道數就可以了。
如果是16位的數據,就需要返回2*channels?,32位就需要4*channels?,64位需要8*channels。
4.小結
到這里關于OpenCV中的CvType的介紹就結束了。
我們如果在使用過程中出現了有關于CvType的錯誤。那么大部分情況下都在于我們對于CvType的陌生造成的。
或者使用了對于通道和深度有要求的算法造成錯誤。