一、概述
1、灰度
灰度使用黑色調表示物體,即用黑色為基准色,不同的飽和度的黑色來顯示圖像。每個灰度對象都具有從 0%(白色)到灰度條100%(黑色)的亮度值。 使用黑白或灰度掃描儀生成的圖像通常以灰度顯示。
像素值量化后用一個字節(8 bits)來表示。如把有黑-灰-白連續變化的灰度值量化為256個灰度級,灰度值的范圍為0~255,表示亮度從深到淺,對應圖像中的顏色為從黑到白。黑白照片包含了黑白之間的所有的灰度色調,每個像素值都是介於黑色和白色之間的256種灰度中的一種。
2、灰度圖
用灰度表示的圖像稱作灰度圖,灰度圖的RGB三通道滿足關系式:R=G=B。
3、灰度圖bmp文件格式
| 偏移量 |
域的名稱 |
大小 |
內容 |
|
| 圖像文件頭 |
0000h |
標識符(Identifier) |
2 bytes |
兩字節的內容用來識別位圖的類型: ‘BM’ : Windows 3.1x, 95, NT, … |
| 0002h |
File Size |
1 dword |
用字節表示的整個文件的大小 |
|
| 0006h |
Reserved |
1 dword |
保留,設置為0 |
|
| 000Ah |
Bitmap Data Offset |
1 dword |
從文件開始到位圖數據開始之間的數據 (bitmap data)之間的偏移量 |
|
| 000Eh |
Bitmap Header Size |
1 dword |
位圖信息頭(Bitmap Info Header)的長度,用來描述 位圖的顏色、壓縮方法等。下面的長度表示: 28h - Windows 3.1x, 95, NT, 0Ch - OS/2 1.x F0h - OS/2 2.x … |
|
| 0012h |
Width |
1 dword |
位圖的寬度,以像素為單位 |
|
| 0016h |
Height |
1 dword |
位圖的高度,以像素為單位 |
|
| 001Ah |
Planes |
1 word |
位圖的位面數 |
|
|
|
001Ch |
Bits Per Pixel |
1 word |
每個像素的位數 1 - Monochrome bitmap 4 - 16 color bitmap 8 - 256 color bitmap 16 - 16bit (high color) bitmap 24 - 24bit (true color) bitmap 32 - 32bit (true color) bitmap |
| 001Eh |
Compression |
1 dword |
壓縮說明: 0 - none (也使用BI_RGB表示) 1 - RLE 8-bit / pixel (也使用BI_RLE4表示) 2 - RLE 4-bit / pixel (也使用BI_RLE8表示) 3 - Bitfields (也使用BI_BITFIELDS表示) |
|
| 0022h |
Bitmap Data Size |
1 dword |
用字節數表示的位圖數據的大小。該數必須是4的倍數 |
|
| 0026h |
HResolution |
1 dword |
用像素/米表示的水平分辨率 |
|
| 002Ah |
VResolution |
1 dword |
用像素/米表示的垂直分辨率 |
|
| 002Eh |
Colors |
1 dword |
位圖使用的顏色數。如8-位/像素表示為100h或者 256. |
|
| 0032h |
Important Colors |
1 dword |
指定重要的顏色數。當該域的值等於顏色數時,表示所有 顏色都一樣重要 |
|
| 調色板數據 |
0036h |
Palette |
N * 4 byte |
調色板規范。對於調色板中的每個表項,這4個字節用下述 方法來描述RGB的值:
|
| 圖像數據 |
0436h |
Bitmap Data |
x bytes |
該域的大小取決於壓縮方法,它包含所有的位圖數據字節 ,這些數據實際就是彩色調色板的索引號 |
example: gray.bmp
1)gray.bmp的圖片信息


2)grap.bmp文件的數據

0000h: 標示符為“BM”
0002h: 文件大小為0x13036,也就是77878字節
0006h: 保留
000Ah:從文件開頭到位圖數據開始的偏移量為0x436
000Eh: 位圖信息頭的長度為0x28
0012h: 位圖的寬度為0x140,也就是寬320個像素
0016h: 位圖的高度為0xF0,也就是高為240個像素
001Ah: 位圖為1幀
001Ch:像素的位數為8位
001Eh: 圖片無壓縮
0022H: 位圖數據的大小為0x12C00,也就是76800個字節
0026H: 水平分辨率為7200
002Ah: 垂直分辨率為7200
002Eh: 位圖使用的顏色數--該域並未賦值
0032h: 重要的顏色數--該域並未賦值
0036h-0435h: 調色板數據
0436h: 位圖數據區
3)解讀
位圖數據區保存的是圖片有效的數據,一個字節的存儲單元對應圖片的一個像素,一個字節的數值代表了對應像素的灰度值。本例圖片是寬320*高240,位圖數據區為76800個字節,算上頭部的控制塊為1078個字節,文件總大小為77878字節。
在顯示的時候,從位圖數據區讀取數據,獲得一個像素的灰度值后,就以灰度值為索引,從調色板區找出灰度值對應的rgb,然后再顯示屏上顯示出該像素。
☆ 注意
windows規定一個掃描行所占的字節數必須是4的倍數,不足的以0填充。假設一個圖片款318個像素,實際上一行占據了320個字節。
4) bmp文件存儲灰度圖像的順序
bmp文件存儲圖像的順序是左下角-->右上角,也就是“從下到上,從左到右”。
那么在顯示bmp圖像時也要遵循這樣的順序,即是:由下而上,由左到右。倘若安裝"從上到下,從左到右",那么顯示的圖像實際上是關於Y軸翻轉的。
測試bmp文件:

WinHex中對應的內容:

二、8位灰度格式轉換到16位565RGB的格式
灰度圖的RGB通道滿足:R=G=B,以灰度值替換RGB三個通道就得到RGB格式的數據。考慮到LCD顯示器的顯示格式是5:6:5(r:g:b),而灰度值是8位灰階,所以有如下的轉換計算公式:
r = GrayValue/256 * 32 = GrayValue/8 = GrayValue >> 3
g = GrayValue/256 * 64 = GrayValue/4 = GrayValue >> 2
b = GrayValue/256 * 32 = GrayValue/8 = GrayValue >> 3
8位灰度值轉換為16位的RGB公式為:
#define GRAYTORGB16(t) ((t >> 3)|((t & ~3) << 3)|((t & ~7) << 8))
三、測試程序代碼
/** * @brief 顯示灰度圖 * @param x,y : 顯示在LCD上的坐標 * pic_name: 存儲在SD卡根目錄下的灰度文件名 * @retval None */ void Lcd_show_bmp(unsigned short int x, unsigned short int y,char *pic_name) { int i, j; int width, height, l_width; BITMAPFILEHEADER bitHead; BITMAPINFOHEADER bitInfoHead; WORD fileType; unsigned int read_num; f_mount(0, &bmpfs[0]); BMP_DEBUG_PRINTF("file mount ok \r\n"); bmpres = f_open( &bmpfsrc , (char *)pic_name, FA_OPEN_EXISTING | FA_READ); if(bmpres == FR_OK) { BMP_DEBUG_PRINTF("Open file success\r\n"); /* 讀取文件頭信息 兩個字節*/ f_read(&bmpfsrc,&fileType,sizeof(WORD),&read_num); /* 判斷是不是bmp文件 "BM"*/ if(fileType != 0x4d42) { BMP_DEBUG_PRINTF("file is not .bmp file!\r\n"); return; } else { BMP_DEBUG_PRINTF("Ok this is .bmp file\r\n"); } /* 讀取BMP文件頭信息*/ f_read(&bmpfsrc,&bitHead,sizeof(tagBITMAPFILEHEADER),&read_num); showBmpHead(&bitHead); /* 讀取位圖信息頭信息 */ f_read(&bmpfsrc,&bitInfoHead,sizeof(BITMAPINFOHEADER),&read_num); showBmpInforHead(&bitInfoHead); } else { BMP_DEBUG_PRINTF("file open fail!\r\n"); return; } width = bitInfoHead.biWidth; height = bitInfoHead.biHeight; /* 計算位圖的實際寬度並確保它為4的倍數 */ l_width = WIDTHBYTES(width); if(l_width > 320) { BMP_DEBUG_PRINTF("\n SORRY, PIC IS TOO BIG (<=320)\n"); return; } /* 設置Lcd Gram 掃描方向為: 右下角-> 左上角 */ Lcd_GramScan(3); /* 開一個圖片大小的窗口*/ LCD_OpenWindow(x, y, width, height); /* 判斷是否是8bit灰度圖 */ if(bitInfoHead.biBitCount == 8) { f_lseek(&bmpfsrc,0x0436); for(i=0;i< height; i++) { /* 讀取一行bmp的數據到數組pColorData里面 */ f_read(&bmpfsrc,pColorData,l_width,&read_num); for(j=0; j<width; j++) //一行有效信息 { unsigned short d; d = pColorData[j]; LCD_WR_Data(GRAYTORGB16(d)); //寫入LCD-GRAM } } } else { BMP_DEBUG_PRINTF("SORRY, THIS PIC IS NOT A 8BITS GRAY Picture!"); return ; } f_close(&bmpfsrc); }
參考資料:bmp頭文件和8 bit 灰度圖的顯示
《STM32庫開發實戰指南》
