本文首發在個人我的博客: blog.shenyuanluo.com/,喜歡的朋友歡迎訂閱。html
YUV: 是一種顏色空間,基於 YUV
的顏色編碼是流媒體的經常使用編碼方式,這種表達方式起初是爲了彩色電視與黑白電視之間的信號兼容;其中git
Y’CbCr:(也稱爲 YUV),是 YUV
的壓縮版本,不一樣之處在於 Y’CbCr
用於 數字圖像 領域,YUV
用於 模擬信號 領域;MPEG
、DVD
、攝像機中常說的 YUV
實際上是 Y'CbCr
,兩者轉換爲 RGBA
的轉換矩陣是不一樣的。github
RGB
輸入信號 紅色 部分與 RGB
信號亮度值之間的差別(即,當前顏色對 紅色 的偏移程度)。RGB
輸入信號 藍色 部分與 RGB
信號亮度值之間的差別(即,當前顏色對 藍色 的偏移程度)。注意: 如無特殊說明,本文討論的
YUV
均指Y'CbCr
。算法
Y
,而後 U
,而後 V
。yuv
交叉存儲。yuv yuv yuv
)和 planar 採樣(yyyy uuuu vvvv
)YUYV YUYV
UYVY UYVY
YYYY UU VV
YUV Y YUV Y
I420:數組
YV12: 性能
Y
是planar採樣,UV
是packet採樣
NV12: 測試
NV21:優化
RGB: 是一種加色模型,將紅(Red
)、綠(Green
)、藍(Blue
)三原色的色光以不一樣的比例相加,以產生多種多樣的色光;且三原色的紅綠藍不可能用其餘單色光合成。編碼
0.0 ~ 1.0
(如在 OpenGL 中對每一個子像素點的表示就是使用這個表示方式)。0 ~ 255
或者 00 ~ FF
(如 RGBA_8888、RGB_565)。bit
表示 0
,1
兩種值,可表示的顏色範圍爲雙色,即最傳統的黑和白;須要調色板,不過調色板只包含兩種顏色。bit
表示,4 個 bit
所可以表示的索引範圍是 0~15
,共 16 個。也就是能夠表示 16 種顏色。即調色板中包含 16 中顏色。bit
表示。8 個 bit
所可以表示的索引範圍是 0~255
,共 256 個。也就是能夠表示 256 種顏色。即調色板中包含 256 種顏色。概述: 每個像素用 16 個 bit
(2個字節)來表示,但最高位不用,R 用 5 個 bit
、G 用 5 個 bit
、B 用 5 個 bit
表示。spa
內存示意圖:
獲取具體像素值方法:(假設 color
爲存儲某一個像素點的變量)
R = color & 0x7C00
// 獲取高字節 5 個 bitG = color & 0x03E0
// 獲取中間的 5 個 bitB = color & 0x001F
// 獲取低字節 5 個 bit概述: 每個像素用 16 個 bit
(2 個字節)來表示,R 用 5 個 bit
、G 用 6 個 bit
、B 用 5 個 bit
表示。
內存示意圖:
獲取具體像素值方法:(假設 color
爲存儲某一個像素點的變量)
R = color & 0xF800
// 獲取高字節 5 個 bitG = color & 0x07E0
// 獲取中間的 6 個 bitB = color & 0x001F
// 獲取低字節 5 個 bit概述: 每個像素用 24 個 bit
(3個字節)來表示,R、G、B 均用 8 bit
表示。
內存示意圖:
獲取具體像素值方法:(假設 color
爲存儲某一個像素點的變量)
R = color & 0x0000FF
G = color & 0x00FF00
B = color & 0xFF0000
概述: 每個像素用 32 個 bit
(4個字節)來表示,R、G、B 均用 8 bit
表示,最後 1 個字節保留
內存示意圖:
獲取具體像素值方法:(假設 color
爲存儲某一個像素點的變量)
R = color & 0x0000FF00
G = color & 0x00FF0000
B = color & 0xFF000000
注意: 這裏的轉換矩陣中,當轉換爲 RGB
讀取 YUV
時,須要將 U(Cb)、V(Cr) 的取值範圍整數表示時,轉換爲:[-128, 127]
;浮點數表示時,轉換爲:[-0.5, 0.5]
。
(這是由於:U(Cb)、V(Cr) 取值範圍是 [﹣128, 127]
,對應的浮點數表示爲 [﹣0.5, 0.5]
;而在存儲時,爲了方便存儲,跟 Y 數據同樣,統一用一個(無符號)字節表示,即取值範圍是 [0, 255]
,對應的浮點數表示爲:[0, 1]
。)
特別注意: 在 OpenGL
內置的矩陣(如 mat2
、mat3
、mat4
)是 列主序,即須要將下列轉換矩陣轉換成 轉置矩陣 !
常規轉換標準:
BT.601 標準:(SD TV)
BT.709 標準:(HD TV)
常規轉換標準:
BT.601 標準:(SD TV)
BT.709 標準:(HD TV)
舉例:YUV ——> RGB 常規轉換矩陣。
r = y + (1.370705 * v);
g = y - (0.337633 * u) - (0.698001 * v);
b = y + (1.732446 * u);
複製代碼
從上述算法,能夠看到存在許多的浮點運算,而在算法優化中,最好能避免浮點運算(比較耗時)來提升效率。
所以,同時對錶達式中全部子項乘以 256
來對結果進行 四捨五入昨晚新的 整數係數,最後再對計算結果再右移 8
位(除以 256
);即,(注意:這裏的轉換是有損的,精度會有所下降)
256 * r = 256 * y + (256 * 1.370705 * v);
256 * g = 256 * y - (256 * 0.337633 * u) - (256 * 0.698001 * v);
256 * b = 256 * y + (256 * 1.732446 * u);
複製代碼
===》
r = ((256 * y + (351 * v))>>8);
g = ((256 * y - (86 * u) - (179 * v))>>8);
b = ((256 * y + (444 * u)) >>8);
複製代碼
從上述算法,能夠看到存在許多的乘法運算,而乘法一樣也很好使,最好能避免乘法運算(使用位移運算代替)來提供效率。
所以,將全部表達式中的子項係數,拆解成整數(該整數必需是 2 的次冪,這樣可使用位移運算)相加的形式。
例如:
351 = 256 + 64 + 16 + 8 + 4 + 2 + 1 = 2^8 + 2^6 + 2^4 + 2^3 + 2^2 + 2^1 + 2^0
複製代碼
===》
r = (((y<<8) + (v<<8) + (v<<6) + (v<<4) + (v<<3) + (v<<2) + (v<<1) + v) >> 8);
g = (((y<<8) - (u<<6) - (u<<4) - (u<<2) - (u<<1) - (v<<7) - (v<<5) - (v<<4) - (v<<1) - v) >> 8);
b = (((y<<8) + (u<<8) + (u<<7) + (u<<5) + (u<<4) + (u<<3) + (u<<2)) >> 8);
複製代碼
在常規轉換表達式中,變量的取值範圍是已經肯定,Y:[0, 255],U:[-128, 127],V:[-128, 127];那麼就可使用一維數組存儲結果來提升效率。
所以,將表達式中相關的變量計算結果分別存儲在 4 個一位數組中,在使用計算時,直接經過數組查詢便可得到表達式相乘結果。
例如:對於表達式 256 * 1.370705 * v
int rv = 0; // 計算 R 值 V 係數
rv = 256 * 1.370705 = 351;
for (int i = 0; i < 256; i++)
{
m_rv[i] = ((i - 128) * rv)>>8;
}
複製代碼
===》
r = y + m_rv[v];
g = y - m_gu[u] - m_gv[v];
b = y + m_bu[u];
複製代碼
I420 ——> RGB24
),但不寫入文件。轉換方式 | 循環次數 | 平均耗時(μs/次) | 平均每幀耗時(μs) |
---|---|---|---|
浮點運算 | 50 | 2837788.36 | 6250.64 |
避免浮點運算 | 50 | 2650935.74 | 5839.07 |
避免乘法運算 | 50 | 3031586.02 | 6677.50 |
查表法 | 50 | 2674598.74 | 5891.19 |