做嵌入式項目的時候,涉及到YUV視頻格式到RGB圖像的轉換,雖然之前有接觸到RGB到都是基於opencv的處理,很多東西並不需要我們過多深入的去探討,現在需要完全拋棄現有的算法程序,需要從內存中一個字節一個字節的處理,這就涉及到各個視頻格式和圖片格式是如何存儲的。看了網上的很多資料,一下資料幫助蠻大。
YUV資料整理:
http://www.fourcc.org/yuv.php YUV和RGB的分析
http://www.cnblogs.com/azraelly/archive/2013/01/01/2841269.html 對YUV的分析
http://ticktick.blog.51cto.com/823160/568928 顯示YUV數據
http://www.cnblogs.com/qinjunni/archive/2012/02/23/2364446.html
YUV
做視頻采集與處理,自然少不了要學會分析YUV數據。因為從采集的角度來說,一般的視頻采集芯片輸出的碼流一般都是YUV數據流的形式,而從視頻處理(例如H.264、MPEG視頻編解碼)的角度來說,也是在原始YUV碼流進行編碼和解析,所以,了解如何分析YUV數據流對於做視頻領域的人而言,至關重要。YUV是指亮度參量和色度參量分開表示的像素格式,而這樣分開的好處就是不但可以避免相互干擾,還可以降低色度的采樣率而不會對圖像質量影響太大。
人眼對色度的敏感程度要低於對亮度的敏感程度。
YUV,分為三個分量,“Y”表示明亮度(Luminance或Luma),也就是灰度值;而“U”和“V” 表示的則是色度(Chrominance或Chroma),作用是描述影像色彩及飽和度,用於指定像素的顏色。與我們熟知的RGB類似,YUV也是一種顏色編碼方法,主要用於電視系統以及模擬視頻領域,它將亮度信息(Y)與色彩信息(UV)分離,沒有UV信息一樣可以顯示完整的圖像,只不過是黑白的,這樣的設計很好地解決了彩色電視機與黑白電視的兼容問題。並且,YUV不像RGB那樣要求三個獨立的視頻信號同時傳輸,所以用YUV方式傳送占用極少的頻寬。
YUV碼流有多種不同的格式,要分析YUV碼流,就必須搞清楚你面對的到底是哪一種格式,並且必須搞清楚這種格式的YUV采樣和分布情況。
YUV格式有兩大類:planar和packed。
對於planar的YUV格式,先連續存儲所有像素點的Y,緊接着存儲所有像素點的U,隨后是所有像素點的V。
對於packed的YUV格式,每個像素點的Y,U,V是連續交叉存儲的。
1. 采樣方式
YUV碼流的存儲格式其實與其采樣的方式密切相關,主流的采樣方式有三種,YUV4:4:4,YUV4:2:2,YUV4:2:0,如何根據其采樣格式來從碼流中還原每個像素點的YUV值,因為只有正確地還原了每個像素點的YUV值,才能通過YUV與RGB的轉換公式提取出每個像素點的RGB值,然后顯示出來。
用三個圖來直觀地表示采集的方式吧,以黑點表示采樣該像素點的Y分量,以空心圓圈表示采用該像素點的UV分量。

先記住下面這段話,以后提取每個像素的YUV分量會用到。
-
YUV 4:4:4采樣,每一個Y對應一組UV分量,每像素32位
-
YUV 4:2:2采樣,每兩個Y共用一組UV分量,每像素16位
-
YUV 4:2:0采樣,每四個Y共用一組UV分量,每像素16位
平常所講的YUV A:B:C的意思一般是指基於4個象素來講,其中Y采樣了A次,U采樣了B次,V采樣了C次.
YUV 格式可以分為打包格式packed format和平面格式planar format。打包格式將YUV分量存放在同一個數組中,通常是幾個相鄰的像素組成一個宏像素(macro-pixel);而平面格使用三個數組分開存放YUV三個分量,就像是一個三維平面一樣。Packed format和planner format的區別在於,packed format中的YUV是混合在一起的,因此就有了UYVY、YUYV等等,他們在碼流中排列的方式有所不同。而對於planner format每一個Y分量,U分量和V分量都是以獨立的平面組織的,也就是說所有的U分量都在Y分量之后出現,而V分量在所有的U分量之后。就像三個大色塊一樣。
2. 存儲方式
下面用圖的形式給出常見的YUV碼流的存儲方式,並在存儲方式后面附有取樣每個像素點的YUV數據的方法,其中,Cb、Cr的含義等同於U、V。因為我們在實驗中芷使用到YUV422的格式,這里只介紹這個,其他的可以去其他博文了找。
(1) YUYV 格式 (屬於YUV422)

YUYV(YUY2)為YUV422采樣的存儲格式中的一種,相鄰的兩個Y共用其相鄰的兩個Cb(U)、Cr(V),分析,對於像素點Y'00、Y'01 而言,其Cb、Cr的值均為 Cb00、Cr00,其他的像素點的YUV取值依次類推。YVYU(YVY2)也一樣,只是UV的位置調換了一下,先V后U。

(2) UYVY 格式 (屬於YUV422)

UYVY格式也是YUV422采樣的存儲格式中的一種,只不過與YUYV不同的是UV的排列順序不一樣而已,還原其每個像素點的YUV值的方法與上面一樣。

(3) YUV422P(屬於YUV422)

YUV422P也屬於YUV422的一種,它是一種Plane模式,即打包模式,並不是將YUV數據交錯存儲,而是先存放所有的Y分量,然后存儲所有的U(Cb)分量,最后存儲所有的V(Cr)分量,如上圖所示。其每一個像素點的YUV值提取方法也是遵循YUV422格式的最基本提取方法,即兩個Y共用一個UV。比如,對於像素點Y'00、Y'01 而言,其Cb、Cr的值均為 Cb00、Cr00。
以YUV420 planar數據為例, 以720×480大小圖象YUV420 planar為例,
其存儲格式是: 共大小為(720×480×3>>1)字節,
分為三個部分:Y,U和V
Y分量: (720×480)個字節
U(Cb)分量:(720×480>>2)個字節
V(Cr)分量:(720×480>>2)個字節
三個部分內部均是行優先存儲,三個部分之間是Y,U,V 順序存儲。
即YUV數據的0--720×480字節是Y分量值,
720×480--720×480×5/4字節是U分量
720×480×5/4 --720×480×3/2字節是V分量。
這里Y分量其實就是我們常說的灰度值,所以需要對圖片進行灰度處理的話,可以直接提取出圖片的Y分量。這點對我們后面的處理很重要。
YUV4:4:4
下面的四個像素為: [Y0 U0 V0] [Y1 U1 V1] [Y2 U2 V2] [Y3 U3 V3]
存放的碼流為: Y0 U0 V0 Y1 U1 V1 Y2 U2 V2 Y3 U3 V3
映射出像素點保持原樣
YUV4:2:2
每個色差信道的抽樣率是亮度信道的一半,所以水平方向的色度抽樣率只是4:4:4的一半。對非壓縮的8比特量化的圖像來說,每個由兩個水平方向相鄰的像素組成的宏像素需要占用4字節內存。
下面的四個像素為:[Y0 U0 V0] [Y1 U1 V1] [Y2 U2 V2] [Y3 U3 V3]
存放的碼流為:Y0 U0 Y1 V1 Y2 U2 Y3 V3
映射出像素點為:[Y0 U0 V1] [Y1 U0 V1] [Y2 U2 V3] [Y3 U2 V3]
YUV 4:1:1
4:1:1的色度抽樣,是在水平方向上對色度進行4:1抽樣。對於低端用戶和消費類產品這仍然是可以接受的。對非壓縮的8比特量化的視頻來說,每個由4個水平方向相鄰的像素組成的宏像素需要占用6字節內存。
原來四個像素為: [Y0 U0 V0] [Y1 U1 V1] [Y2 U2 V2] [Y3 U3 V3]
存放的碼流為: Y0 U0 Y1 Y2 V2 Y3
還原出像素點為:[Y0 U0 V2] [Y1 U0 V2] [Y2 U0 V2] [Y3 U0 V2]
用6個YUV分量描述了原來的12個YUV分量,因此壓縮比為1/2,平均來講,就是用了12bit表示了一個象素點,原來YUV(8bit*3)是24bit。
YUV4:2:0
4:2:0並不意味着只有Y,Cb而沒有Cr分量。它指得是對每行掃描線來說,只有一種色度分量以2:1的抽樣率存儲。相鄰的掃描行存儲不同的色度分 量,也就是說,如果一行是4:2:0的話,下一行就是4:0:2,再下一行是4:2:0...以此類推。對每個色度分量來說,水平方向和豎直方向的抽樣率 都是2:1,所以可以說色度的抽樣率是4:1。對非壓縮的8比特量化的視頻來說,每個由2x2個2行2列相鄰的像素組成的宏像素需要占用6字節內存。
下面八個像素為:[Y0 U0 V0] [Y1 U1 V1] [Y2 U2 V2] [Y3 U3 V3] [Y5 U5 V5] [Y6 U6 V6] [Y7U7 V7] [Y8 U8 V8]
存放的碼流為:Y0 U0 Y1 Y2 U2 Y3 Y5 V5 Y6 Y7 V7 Y8
映射出的像素點為:[Y0 U0 V5] [Y1 U0 V5] [Y2 U2 V7] [Y3 U2 V7] [Y5 U0 V5] [Y6 U0 V5] [Y7U2 V7] [Y8 U2 V7]
RGB
計算機彩色顯示器顯示色彩的原理與彩色電視機一樣,都是采用R(Red)、G(Green)、B(Blue)相加混色的原理:通過發射出三種不同強度的電子束,使屏幕內側覆蓋的紅、綠、藍磷光材料發光而產生色彩。這種色彩的表示方法稱為RGB色彩空間表示(它也是多媒體計算機技術中用得最 多的一種色彩空間表示方法)。根據色度學的介紹,不同波長的單色光會引起不同的彩色感覺,但相同的彩色感覺卻可以來源於不同的光譜成分組合。自然界中幾乎所有的顏色都能用三種基本彩色混合配出,在彩色電視技術中選擇紅色、綠色、和藍色作為三基色。其他的顏色都可以用紅色、綠色和藍色按照不同的比例混合而成。所選取的紅色、綠色和藍色三基色空間。簡稱為RGB顏色空間。
RGB565 每個像素用16位表示,RGB分量分別使用5位、6位、5位
RGB555 每個像素用16位表示,RGB分量都使用5位(剩下1位不用)
RGB24 每個像素用24位表示,RGB分量各使用8位
RGB32 每個像素用32位表示,RGB分量各使用8位(剩下8位不用)
ARGB32 每個像素用32位表示,RGB分量各使用8位(剩下的8位用於表示Alpha通道值)
RGB565(我們使用的格式)
使用16位表示一個像素,這16位中的5位用於R,6位用於G,5位用於B。
程序中通常使用一個字(WORD,一個字等於兩個字節)來操作一個像素。當讀出一個像素后,這個字的各個位意義如下:
高字節 低字節
R R R R R G G G G G G B B B B B
可以組合使用屏蔽字和移位操作來得到RGB各分量的值:
#define RGB565_MASK_RED 0xF800
#define RGB565_MASK_GREEN 0x07E0
#define RGB565_MASK_BLUE 0x001F
R = (wPixel & RGB565_MASK_RED) >> 11; // 取值范圍0-31
G = (wPixel & RGB565_MASK_GREEN) >> 5; // 取值范圍0-63
B = wPixel & RGB565_MASK_BLUE; // 取值范圍0-31
#define RGB(r,g,b) (unsigned int)( (r|0x08 << 11) | (g|0x08 << 6) | b|0x08 )
#define RGB(r,g,b) (unsigned int)( (r|0x08 << 10) | (g|0x08 << 5) | b|0x08 )
該代碼可以解決24位與16位相互轉換的問題
RGB555
是另一種16位的RGB格式,RGB分量都用5位表示(剩下的1位不用)。
使用一個字讀出一個像素后,這個字的各個位意義如下:
高字節 低字節
X R R R R G G G G G B B B B B (X表示不用,可以忽略)
RGB24使用24位來表示一個像素,RGB分量都用8位表示,取值范圍為0-255
RGB32使用32位來表示一個像素,RGB分量各用去8位,剩下的8位不用
RGB24
RGB24使用24位來表示一個像素,RGB分量都用8位表示,取值范圍為0-255。注意在內存中RGB各分量的排列順序為:BGR BGR BGR…。通常可以使用RGBTRIPLE數據結構來操作一個像素,它的定義為:
typedef struct tagRGBTRIPLE {
BYTE rgbtBlue; // 藍色分量
BYTE rgbtGreen; // 綠色分量
BYTE rgbtRed; // 紅色分量
} RGBTRIPLE;
RGB32
RGB32使用32位來表示一個像素,RGB分量各用去8位,剩下的8位用作Alpha通道或者不用。(ARGB32就是帶Alpha通道的RGB24。)注意在內存中RGB各分量的排列順序為:BGRA BGRA BGRA…。通常可以使用RGBQUAD數據結構來操作一個像素,它的定義為:
typedef struct tagRGBQUAD {
BYTE rgbBlue; // 藍色分量
BYTE rgbGreen; // 綠色分量
BYTE rgbRed; // 紅色分量
BYTE rgbReserved; // 保留字節(用作Alpha通道或忽略)
} RGBQUAD。
