BMP 轉 YUV (BMP2YUV)
阿新 • • 發佈:2019-02-09
本文介紹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.0813BYUV檔案的格式
轉換後的YUV資料需要存成YUV檔案(在這裡是YUV420P格式)。YUV檔案的格式很簡單,先連續存Y,然後U,然後V,如圖所示。