天然界的顏色變幻無窮,爲了給顏色一個量化的衡量標準,就須要創建色彩空間模型來描述各類各樣的顏色,因爲人對色彩的感知是一個複雜的生理和心理聯合做用的過程,因此在不一樣的應用領域中爲了更好更準確的知足各自的需求,就出現了各類各樣的色彩空間模型來量化的描述顏色。咱們比較常接觸到的就包括 RGB / CMYK / YIQ / YUV / HSI等等。html
對於數字電子多媒體領域來講,咱們常常接觸到的色彩空間的概念,主要是RGB , YUV這兩種(實際上,這兩種體系包含了許多種具體的顏色表達方式和模型,如sRGB, Adobe RGB, YUV422, YUV420 …), RGB是按三基色加光系統的原理來描述顏色,而YUV則是按照 亮度,色差的原理來描述顏色。算法
即便只是RGB YUV這兩大類色彩空間,所涉及到的知識也是十分豐富複雜的,自知不具有足夠的相關專業知識,因此本文主要針對工程領域的應用及算法進行討論。數組
對於YUV模型,實際上不少時候,咱們是把它和YIQ / YCrCb模型混爲一談的。數據結構
實際上,YUV模型用於PAL制式的電視系統,Y表示亮度,UV並不是任何單詞的縮寫。性能
YIQ模型與YUV模型相似,用於NTSC制式的電視系統。YIQ顏色空間中的I和Q份量至關於將YUV空間中的UV份量作了一個33度的旋轉。測試
YCbCr顏色空間是由YUV顏色空間派生的一種顏色空間,主要用於數字電視系統中。從RGB到YCbCr的轉換中,輸入、輸出都是8位二進制格式。編碼
三者與RGB的轉換方程以下:設計
RGB -> YUV:視頻
實際上也就是:htm
Y=0.30R+0.59G+0.11B , U=0.493(B-Y) , V=0.877(R-Y)
RGB -> YIQ:
RGB -> YCrCb:
從公式中,咱們關鍵要理解的一點是,UV / CbCr信號實際上就是藍色差信號和紅色差信號,進而言之,實際上必定程度上間接的表明了藍色和紅色的強度,理解這一點對於咱們理解各類顏色變換處理的過程會有很大的幫助。
咱們在數字電子多媒體領域所談到的YUV格式,實際上準確的說,是以YcrCb色彩空間模型爲基礎的具備多種存儲格式的一類顏色模型的家族(包括YUV444 / YUV422 / YUV420 / YUV420P等等)。並非傳統意義上用於PAL制模擬電視的YUV模型。這些YUV模型的區別主要在於UV數據的採樣方式和存儲方式,這裏就不詳述。
而在Camera Sensor中,最經常使用的YUV模型是 YUV422格式,由於它採用4個字節描述兩個像素,能和RGB565模型比較好的兼容。有利於Camera Sensor和Camera controller的軟硬件接口設計。
這裏指的YUV實際是YcrCb了,YUV2RGB的轉換公式自己是很簡單的,可是牽涉到浮點運算,因此,若是要實現快速算法,算法結構自己沒什麼好研究的了,主要是採用整型運算或者查表來加快計算速度。
首先能夠推導獲得轉換公式爲:
R = Y + 1.4075 *(V-128)
G = Y – 0.3455 *(U –128) – 0.7169 *(V –128)
B = Y + 1.779 *(U – 128)
要用整型運算代替浮點運算,固然是要用移位的辦法了,咱們能夠很容易獲得下列算法:
u = YUVdata[UPOS] - 128;
v = YUVdata[VPOS] - 128;
rdif = v + ((v * 103) >> 8);
invgdif = ((u * 88) >> 8) +((v * 183) >> 8);
bdif = u +( (u*198) >> 8);
r = YUVdata[YPOS] + rdif;
g = YUVdata[YPOS] - invgdif;
b = YUVdata[YPOS] + bdif;
爲了防止出現溢出,還須要判錯計算的結果是否在0-255範圍內,作相似下面的判斷。
if (r>255)
r=255;
if (r<0)
r=0;
要從RGB24轉換成RGB565數據還要作移位和或運算:
RGBdata[1] =( (r & 0xF8) | ( g >> 5) );
RGBdata[0] =( ((g & 0x1C) << 3) | ( b >> 3) );
查表法首先能夠想到的就是用查表替代上述整型算法中的乘法運算。
rdif = fac_1_4075[u];
invgdif = fac_m_0_3455[u] + fac_m_0_7169[v];
bdif = fac_1_779[u];
這裏一共須要4個1維數組,下標從0開始到255,表格共佔用約1K的內存空間。uv能夠不須要作減128的操做了。在事先計算對應的數組元素的值的時候計算在內就行了。
對於每一個像素,部分查表法用查表替代了2次減法運算和4次乘法運算,4次移位運算。可是,依然須要屢次加法運算和6次比較運算和可能存在的賦值操做,相對第一種方法運算速度提升並不明顯。
那麼是否能夠由YUV直接查表獲得對應的RGB值呢?乍一看彷佛不太可能,以最複雜的G的運算爲例,由於G與YUV三者都相關,因此相似 G=YUV2G[Y][U][V]這樣的算法,一個三維下標尺寸都爲256的數組就須要佔用2的24次方約16兆空間,絕對是無法接受的。因此目前多數都是採用部分查表法。
可是,若是咱們仔細分析就能夠發現,對於G咱們實際上徹底沒有必要採用三維數組,由於Y只與UV運算的結果相關,與UV的個體無關,因此咱們能夠採用二次查表的方法將G的運算簡化爲對兩個二維數組的查表操做,以下:
G = yig2g_table[ y ][ uv2ig_table[ u ][ v ] ];
而RB自己就只和YU或YV相關,因此這樣咱們一共須要4個8*8的二維表格,須要佔用4乘2的16次方共256K內存。基本能夠接受。可是對於手機這樣的嵌入式運用來講,仍是略有些大了。
進一步分析,咱們能夠看到,由於在手機等嵌入式運用上咱們最終是要把數據轉換成RGB565格式送到LCD屏上顯示的,因此,對於RGB三份量來講,咱們根本不須要8bit這麼高的精度,爲了簡單和運算的統一塊兒見,對每一個份量咱們其實只須要高6bit的數據就足夠了,因此咱們能夠進一步把表格改成4個6*6的二維表格,這樣一共只須要佔用16K內存!在計算表格元素值的時候還能夠把最終的溢出判斷也事先作完。最後的算法以下:
y = (YUVdata[Y1POS] >> 2);
u = (YUVdata[UPOS] >> 2);
v = (YUVdata[VPOS] >> 2);
r = yv2r_table[ y ][ v ];
g = yig2g_table[ y ][ uv2ig_table[ u ][ v ] ];
b = yu2b_table[ y ][ u ];
RGBdata[1] =( (r & 0xF8) | ( g >> 5) );
RGBdata[0] =( ((g & 0x1C) << 3) | ( b >> 3) );
這樣相對部分查表法,咱們增長了3次移位運算,而進一步減小了4次加法運算和6次比較賦值操做。
在計算表格元素數值的時候,要考慮舍入和偏移等因數使得計算的中間結果知足數組下標非負的要求,須要必定的技巧。
採用徹底查表法,相對於第一種算法,最終運算速度能夠有比較明顯的提升,具體性能能提升多少,要看所在平臺的CPU運算速度和內存存取速度的相對比例。內存存取速度越快,用查表法帶來的性能改善越明顯。在個人PC上測試的結果性能大約能提升35%。而在某ARM平臺上測試只提升了約15%。
實際上,上述算法:
RGBdata[1] =( (r & 0xF8) | ( g >> 5) );
RGBdata[0] =( ((g & 0x1C) << 3) | ( b >> 3) );
中的 (r & 0xF8) 和 ( b >> 3) 等運算也徹底能夠在表格中事先計算出來。另外,YU / YV的取值實際上不可能覆蓋滿6*6的範圍,中間有些點是永遠取不到的無輸入,RB的運算也能夠考慮用5*5的表格。這些均可能進一步提升運算的速度,減少表格的尺寸。
另外,在嵌入式運用中,若是可能儘可能將表格放在高速內存如SRAM中應該比放在SDRAM中更加能發揮查表法的優點。
目前以爲這個是無法將3維表格的查表運算化簡爲2維表格的查表運算了。只能用部分查表法替代其中的乘法運算。
計算機彩色顯示器顯示色彩的原理與彩色電視機同樣,都是採用R(Red)、G(Green)、B(Blue)相加混色的原理:經過發射出三種不一樣強度的電子束,使屏幕內側覆蓋的紅、綠、藍磷光材料發光而產生色彩。這種色彩的表示方法稱爲RGB色彩空間表示(它也是多媒體計算機技術中用得最多的一種色彩空間表示方法)。
根據三基色原理,任意一種色光F均可以用不一樣份量的R、G、B三色相加混合而成。
F = r [ R ] + g [ G ] + b [ B ]
其中,r、g、b分別爲三基色參與混合的係數。當三基色份量都爲0(最弱)時混合爲黑色光;而當三基色份量都爲k(最強)時混合爲白色光。調整r、g、b三個係數的值,能夠混合出介於黑色光和白色光之間的各類各樣的色光。
那麼YUV又從何而來呢?在現代彩色電視系統中,一般採用三管彩色攝像機或彩色CCD攝像機進行攝像,而後把攝得的彩色圖像信號經分色、分別放大校訂後獲得RGB,再通過矩陣變換電路獲得亮度信號Y和兩個色差信號R-Y(即U)、B-Y(即V),最後發送端將亮度和色差三個信號分別進行編碼,用同一信道發送出去。這種色彩的表示方法就是所謂的YUV色彩空間表示。
採用YUV色彩空間的重要性是它的亮度信號Y和色度信號U、V是分離的。若是隻有Y信號份量而沒有U、V份量,那麼這樣表示的圖像就是黑白灰度圖像。彩色電視採用YUV空間正是爲了用亮度信號Y解決彩色電視機與黑白電視機的兼容問題,使黑白電視機也能接收彩色電視信號。
YUV與RGB相互轉換的公式以下(RGB取值範圍均爲0-255):
Y = 0.299R + 0.587G + 0.114B
U = -0.147R - 0.289G + 0.436B
V = 0.615R - 0.515G - 0.100B
R = Y + 1.14V
G = Y - 0.39U - 0.58V
B = Y + 2.03U
在DirectShow中,常見的RGB格式有RGB一、RGB四、RGB八、RGB56五、RGB55五、RGB2四、RGB3二、ARGB32等;常見的YUV格式有YUY二、YUYV、YVYU、UYVY、AYUV、Y41P、Y4十一、Y2十一、IF0九、IYUV、YV十二、YVU九、YUV4十一、YUV420等。做爲視頻媒體類型的輔助說明類型(Subtype),它們對應的GUID見表2.3。
表2.3 常見的RGB和YUV格式
GUID 格式描述
MEDIASUBTYPE_RGB1 2色,每一個像素用1位表示,須要調色板
MEDIASUBTYPE_RGB4 16色,每一個像素用4位表示,須要調色板
MEDIASUBTYPE_RGB8 256色,每一個像素用8位表示,須要調色板
MEDIASUBTYPE_RGB565 每一個像素用16位表示,RGB份量分別使用5位、6位、5位
MEDIASUBTYPE_RGB555 每一個像素用16位表示,RGB份量都使用5位(剩下的1位不用)
MEDIASUBTYPE_RGB24 每一個像素用24位表示,RGB份量各使用8位
MEDIASUBTYPE_RGB32 每一個像素用32位表示,RGB份量各使用8位(剩下的8位不用)
MEDIASUBTYPE_ARGB32 每一個像素用32位表示,RGB份量各使用8位(剩下的8位用於表示Alpha通道值)
MEDIASUBTYPE_YUY2 YUY2格式,以4:2:2方式打包
MEDIASUBTYPE_YUYV YUYV格式(實際格式與YUY2相同)
MEDIASUBTYPE_YVYU YVYU格式,以4:2:2方式打包
MEDIASUBTYPE_UYVY UYVY格式,以4:2:2方式打包
MEDIASUBTYPE_AYUV 帶Alpha通道的4:4:4 YUV格式
MEDIASUBTYPE_Y41P Y41P格式,以4:1:1方式打包
MEDIASUBTYPE_Y411 Y411格式(實際格式與Y41P相同)
MEDIASUBTYPE_Y211 Y211格式
MEDIASUBTYPE_IF09 IF09格式
MEDIASUBTYPE_IYUV IYUV格式
MEDIASUBTYPE_YV12 YV12格式
MEDIASUBTYPE_YVU9 YVU9格式
下面分別介紹各類RGB格式。
¨ RGB一、RGB四、RGB8都是調色板類型的RGB格式,在描述這些媒體類型的格式細節時,一般會在BITMAPINFOHEADER數據結構後面跟着一個調色板(定義一系列顏色)。它們的圖像數據並非真正的顏色值,而是當前像素顏色值在調色板中的索引。以RGB1(2色位圖)爲例,好比它的調色板中定義的兩種顏色值依次爲0x000000(黑色)和0xFFFFFF(白色),那麼圖像數據001101010111…(每一個像素用1位表示)表示對應各像素的顏色爲:黑黑白白黑白黑白黑白白白…。
¨ 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
¨ RGB555是另外一種16位的RGB格式,RGB份量都用5位表示(剩下的1位不用)。使用一個字讀出一個像素後,這個字的各個位意義以下:
高字節 低字節
X R R R R G G G G G B B B B B (X表示不用,能夠忽略)
能夠組合使用屏蔽字和移位操做來獲得RGB各份量的值:
#define RGB555_MASK_RED 0x7C00
#define RGB555_MASK_GREEN 0x03E0
#define RGB555_MASK_BLUE 0x001F
R = (wPixel & RGB555_MASK_RED) >> 10; // 取值範圍0-31
G = (wPixel & RGB555_MASK_GREEN) >> 5; // 取值範圍0-31
B = wPixel & RGB555_MASK_BLUE; // 取值範圍0-31
¨ RGB24使用24位來表示一個像素,RGB份量都用8位表示,取值範圍爲0-255。注意在內存中RGB各份量的排列順序爲:BGR BGR BGR…。一般可使用RGBTRIPLE數據結構來操做一個像素,它的定義爲:
typedef struct tagRGBTRIPLE {
BYTE rgbtBlue; // 藍色份量
BYTE rgbtGreen; // 綠色份量
BYTE rgbtRed; // 紅色份量
} RGBTRIPLE;
¨ RGB32使用32位來表示一個像素,RGB份量各用去8位,剩下的8位用做Alpha通道或者不用。(ARGB32就是帶Alpha通道的RGB32。)注意在內存中RGB各份量的排列順序爲:BGRA BGRA BGRA…。一般可使用RGBQUAD數據結構來操做一個像素,它的定義爲:
typedef struct tagRGBQUAD {
BYTE rgbBlue; // 藍色份量
BYTE rgbGreen; // 綠色份量
BYTE rgbRed; // 紅色份量
BYTE rgbReserved; // 保留字節(用做Alpha通道或忽略)
} RGBQUAD;
下面介紹各類YUV格式。YUV格式一般有兩大類:打包(packed)格式和平面(planar)格式。前者將YUV份量存放在同一個數組中,一般是幾個相鄰的像素組成一個宏像素(macro-pixel);然後者使用三個數組分開存放YUV三個份量,就像是一個三維平面同樣。表2.3中的YUY2到Y211都是打包格式,而IF09到YVU9都是平面格式。(注意:在介紹各類具體格式時,YUV各份量都會帶有下標,如Y0、U0、V0表示第一個像素的YUV份量,Y一、U一、V1表示第二個像素的YUV份量,以此類推。)
¨ YUY2(和YUYV)格式爲每一個像素保留Y份量,而UV份量在水平方向上每兩個像素採樣一次。一個宏像素爲4個字節,實際表示2個像素。(4:2:2的意思爲一個宏像素中有4個Y份量、2個U份量和2個V份量。)圖像數據中YUV份量排列順序以下:
Y0 U0 Y1 V0 Y2 U2 Y3 V2 …
¨ YVYU格式跟YUY2相似,只是圖像數據中YUV份量的排列順序有所不一樣:
Y0 V0 Y1 U0 Y2 V2 Y3 U2 …
¨ UYVY格式跟YUY2相似,只是圖像數據中YUV份量的排列順序有所不一樣:
U0 Y0 V0 Y1 U2 Y2 V2 Y3 …
¨ AYUV格式帶有一個Alpha通道,而且爲每一個像素都提取YUV份量,圖像數據格式以下:
A0 Y0 U0 V0 A1 Y1 U1 V1 …
¨ Y41P(和Y411)格式爲每一個像素保留Y份量,而UV份量在水平方向上每4個像素採樣一次。一個宏像素爲12個字節,實際表示8個像素。圖像數據中YUV份量排列順序以下:
U0 Y0 V0 Y1 U4 Y2 V4 Y3 Y4 Y5 Y6 Y8 …
¨ Y211格式在水平方向上Y份量每2個像素採樣一次,而UV份量每4個像素採樣一次。一個宏像素爲4個字節,實際表示4個像素。圖像數據中YUV份量排列順序以下:
Y0 U0 Y2 V0 Y4 U4 Y6 V4 …
¨ YVU9格式爲每一個像素都提取Y份量,而在UV份量的提取時,首先將圖像分紅若干個4 x 4的宏塊,而後每一個宏塊提取一個U份量和一個V份量。圖像數據存儲時,首先是整幅圖像的Y份量數組,而後就跟着U份量數組,以及V份量數組。IF09格式與YVU9相似。
¨ IYUV格式爲每一個像素都提取Y份量,而在UV份量的提取時,首先將圖像分紅若干個2 x 2的宏塊,而後每一個宏塊提取一個U份量和一個V份量。YV12格式與IYUV相似。
¨ YUV4十一、YUV420格式多見於DV數據中,前者用於NTSC制,後者用於PAL制。YUV411爲每一個像素都提取Y份量,而UV份量在水平方向上每4個像素採樣一次。YUV420並不是V份量採樣爲0,而是跟YUV411相比,在水平方向上提升一倍色差採樣頻率,在垂直方向上以U/V間隔的方式減少一半色差採樣,如圖2.12所示.