1. 程式人生 > >BMP 轉 YUV (BMP2YUV)

BMP 轉 YUV (BMP2YUV)

本文介紹BMP 轉 YUV。其實這是以前“資料壓縮”實驗課上的內容,前幾天有人問我相關的問題,突然發現自己有一段時間沒有接觸BMP也有些生疏了,因此翻出資料總結一下。

BMP檔案格式解析

點陣圖檔案(Bitmap-File,BMP)格式是Windows採用的影象檔案儲存格式,在Windows環境下執行的所有影象處理軟體都支援這種格式。BMP點陣圖檔案預設的副檔名是bmp或者dib。BMP檔案大體上分為四個部分:


點陣圖檔案頭主要包括:
typedef struct tagBITMAPFILEHEADER {
WORD bfType; /* 說明檔案的型別 */
DWORD bfSize; /* 說明檔案的大小,用位元組為單位 */
WORD bfReserved1; /* 保留,設定為0 */
WORD bfReserved2; /* 保留,設定為0 */
DWORD bfOffBits; /* 說明從BITMAPFILEHEADER結構開始到實際的影象資料之間的位元組偏移量 */
} BITMAPFILEHEADER;

點陣圖資訊頭主要包括:
typedef struct tagBITMAPINFOHEADER {
DWORD biSize; /* 說明結構體所需位元組數 */
LONG biWidth; /* 以畫素為單位說明影象的寬度 */
LONG biHeight; /* 以畫素為單位說明影象的高速 */
WORD biPlanes; /* 說明位面數,必須為1 */
WORD biBitCount; /* 說明位數/畫素,1、2、4、8、24 */
DWORD biCompression; /* 說明影象是否壓縮及壓縮型別BI_RGB,BI_RLE8,BI_RLE4,BI_BITFIELDS */
DWORD biSizeImage; /* 以位元組為單位說明影象大小,必須是4的整數倍*/
LONG biXPelsPerMeter; /*目標裝置的水平解析度,畫素/米 */
LONG biYPelsPerMeter; /*目標裝置的垂直解析度,畫素/米 */
DWORD biClrUsed; /* 說明影象實際用到的顏色數,如果為0,則顏色數為2的biBitCount次方 */
DWORD biClrImportant; /*說明對影象顯示有重要影響的顏色索引的數目,如果是0,表示都重要。*/
} BITMAPINFOHEADER;

調色盤實際上是一個數組,它所包含的元素與點陣圖所具有的顏色數相同,決定於biClrUsed和biBitCount欄位。陣列中每個元素的型別是一個RGBQUAD結構。真彩色無調色盤部分。
typedef struct tagRGBQUAD {
BYTE rgbBlue; /*指定藍色分量*/
BYTE rgbGreen; /*指定綠色分量*/
BYTE rgbRed; /*指定紅色分量*/
BYTE rgbReserved; /*保留,指定為0*/
} RGBQUAD;

緊跟在調色盤之後的是影象資料位元組陣列。對於用到調色盤的點陣圖,影象資料就是該畫素顏色在調色盤中的索引值(邏輯色)。對於真彩色圖,影象資料就是實際的R、G、B值。影象的每一掃描行由表示影象畫素的連續的位元組組成,每一行的位元組數取決於影象的顏色數目和用畫素表示的影象寬度。規定每一掃描行的位元組數必需是4的整倍數,也就是DWORD對齊的。掃描行是由底向上儲存的,這就是說,陣列中的第一個位元組表示點陣圖左下角的畫素,而最後一個位元組表示點陣圖右上角的畫素。

讀取

BMP檔案,提取RGB資料的流程

流程如下圖所示:


在這裡需要注意的的是,根據BMP每畫素所佔的位元數不同(8,16,32 bpp),分為不同的處理方法,如下圖所示。


下面看看16bpp的BMP檔案操作:

R,G,B在16bit中所佔的位數如下圖所示


for (Loop = 0;Loop < height * width;Loop +=2)
{
       *rgbDataOut = (Data[Loop]&0x1F)<<3;
       *(rgbDataOut + 1) = ((Data[Loop]&0xE0)>>2) + 			((Data[Loop+1]&0x03)<<6);
       *(rgbDataOut + 2) = (Data[Loop+1]&0x7C)<<1;
       rgbDataOut +=3;
}
1-8bpp的BMP檔案操作:
int shiftCnt = 1;
while (mask)
{
unsigned char index = mask == 0xFF ? Data[Loop] : ((Data[Loop] & mask)>>(8 - shiftCnt * info_h.biBitCount));
* rgbDataOut = pRGB[index].rgbBlue;
* (rgbDataOut+1) = pRGB[index].rgbGreen;
* (rgbDataOut+2) = pRGB[index].rgbRed;
if(info_h.biBitCount == 8)	mask = 0;
Else 	mask >>= info_h.biBitCount;
rgbDataOut+=3;
shiftCnt ++;
}

BMP轉換為YUV RGB到色差訊號的轉換如下所示: Y=0.2990R+0.5870G+0.1140B R-Y=0.7010R-0.5870G-0.1140B B-Y=-0.2990R-0.5870G+0.8860B

為了使色差訊號的動態範圍控制在0.5之間,需要進行歸一化,對色差訊號引入壓縮係數。歸一化後的色差訊號為:

U=-0.1684R-0.3316G+0.5B V=0.5R-0.4187G-0.0813B

YUV檔案的格式

轉換後的YUV資料需要存成YUV檔案(在這裡是YUV420P格式)。YUV檔案的格式很簡單,先連續存Y,然後U,然後V,如圖所示。