本篇文章首先介紹了bmp圖片格式,主要參考wiki上的內容,包括bmp文件的存儲方式,對於一些常見的bmp文件格式都給了例子,並且對8位 16位RGB555 16位RGB565格式的bmp文件進行了簡單分析,最后的代碼可以將8位,16位,24位,32位色彩深度的bmp文件轉化位8位灰度圖片,用作后續文章中算法的測試圖片。
Bmp file structure
Bitmap file header
DIB header (bitmap information header)
compression method
色彩深度 1bpp = 1位色彩深度,存儲一個像素點使用1位,可以表示兩種顏色
bpp <= 8 必須有調色板(color table)
bpp = 1 調色板 2 * 4 字節
bpp = 4 調色板 16 * 4 字節
bpp = 8 調色板 256 * 4 字節
In most cases, each entry in the color table occupies 4 bytes, in the order blue, green, red, 0x00 (see below for exceptions).The color table is a block of bytes (a table) listing the colors used by the image. Each pixel in an indexed color image is described by a number of bits (1, 4, or 8) which is an index of a single color described by this table. The purpose of the color palette in indexed color bitmaps is to inform the application about the actual color that each of these index values corresponds to. The purpose of the color table in non-indexed (non-palettized) bitmaps is to list the colors used by the bitmap for the purposes of optimization on devices with limited color display capability and to facilitate future conversion to different pixel formats and paletization.
<https://en.wikipedia.org/wiki/BMP_file_format>
調色板數據格式 [blue][green][red][alpha = 0x00]
位圖格式分析
1bpp(單色位圖)
4bpp(16色位圖)
8bpp(256色位圖)
bmp頭文件和DIB頭
0x00000436 位圖數據偏移1078字節 調色板1078 - 54 = 1024字節 調色板為256個數據的數組,每個數組4字節
54字節之后的內容為調色板,1078字節之后的內容為位圖數據
調色板數據為這副圖片中用到的所有顏色數據,位圖數據塊的內容為調色板數據的索引
16bpp(RGB555 無壓縮compression = BI_RGB,無調色板,無掩碼bitmask)
二進制文件為
Bmp頭文件
0x424d bmp文件開頭
0x004b0038 bmp文件大小 為4915256字節
四個字節保留位
0x00000036 位圖數據地址偏移 54字節
DIB頭
0x00000028 DIB頭大小 40字節
0x00000780 寬度1920像素
0x00000500 高度1280像素(有符號整數,若<0,解析圖片時上下翻轉)
0x0001 調色板的數量1
0x0010 每個像素點的位數 16位
0x00000000 壓縮方式,無壓縮
0x004b0002 像素數據大小 4915202 = 4915256 - 54
0x00000b12 橫向分辨率每米2834像素
0x00000b12 縱向分辨率
0x00000000 調色板顏色數
0x00000000 重要顏色數
其余為位圖數據
16bpp(RGB565 壓縮方式BI_BITFIELDS 無調色板 有附加掩碼位bitmask)
0x00000042 位圖數據偏移66字節 存在66 - 54 = 12字節的附加掩碼位
0x00000003 壓縮方式BI_BITFIELDS
0x0000f800[R] 附加掩碼位,讀取一個像素之后,可以分別用掩碼“與”上像素值,
0x000007e0[G] 從而提取出想要的顏色分量
0x0000001f[B] 例如 像素值 & 0xf800 為紅色分量的值
66字節以后為位圖數據
算法實現
8位色彩深度轉灰度圖片
1 void bpp82grayscale(long height, long width, FILE* fp, short** the_image, int pad, 2 const char* file_name, struct bitmapheader* bmheader) 3 { 4 union colortable_union* colortable = NULL; 5 unsigned char pixel_index; 6 7 printf("bpp8\n"); 8 colortable = read_allocate_colortable(file_name, bmheader); 9 for(int i=0; i<height; i++){ 10 for(int j=0; j<width; j++){ 11 fread(&pixel_index, 1, 1, fp); 12 // printf("%u\n", pixel_index); 13 the_image[i][j] = ((colortable[pixel_index].colortable.red) + 14 (colortable[pixel_index].colortable.blue) + 15 (colortable[pixel_index].colortable.green)) / 3; 16 } /* ends loop over j */ 17 if(pad != 0){ 18 fseek(fp, pad, SEEK_CUR); 19 } /* ends if pad 1= 0 */ 20 } /* ends loop over i */ 21 free_colortable(colortable); 22 }
rgb565轉灰度圖
1 void rgb5652grayscale(long height, long width, FILE* fp, short** the_image, int pad) 2 { 3 union rgb565_union pixel; 4 5 printf("rgb565\n"); 6 for(int i=0; i<height; i++){ 7 for(int j=0; j<width; j++){ 8 fread(&pixel, 1, 2, fp); 9 10 the_image[i][j] = ((pixel.rgb565_struct.red<<3) + 11 (pixel.rgb565_struct.green<<2) + 12 (pixel.rgb565_struct.blue<<3)) / 3; 13 } /* ends loop over j */ 14 if(pad != 0){ 15 fseek(fp, pad, SEEK_CUR); 16 } /* ends if pad 1= 0 */ 17 } /* ends loop over i */ 18 }
rgb555轉灰度圖
1 void rgb5552grayscale(long height, long width, FILE* fp, short** the_image, int pad) 2 { 3 union rgb555_union pixel; 4 5 printf("rgb555\n"); 6 for(int i=0; i<height; i++){ 7 for(int j=0; j<width; j++){ 8 fread(&pixel, 1, 2, fp); 9 the_image[i][j] = ((pixel.rgb555_struct.red<<3) + 10 (pixel.rgb555_struct.green<<3) + 11 (pixel.rgb555_struct.blue<<3)) / 3; 12 } /* ends loop over j */ 13 if(pad != 0){ 14 fseek(fp, pad, SEEK_CUR); 15 } /* ends if pad 1= 0 */ 16 } /* ends loop over i */ 17 }
24位色彩深度轉灰度圖
1 void bpp242grayscale(long height, long width, FILE* fp, short** the_image, int pad) 2 { 3 union bpp24_union pixel; 4 5 printf("bpp24\n"); 6 for(int i=0; i<height; i++){ 7 for(int j=0; j<width; j++){ 8 fread(&pixel, 1, 3, fp); 9 the_image[i][j] = ((pixel.bpp24_struct.red) + 10 (pixel.bpp24_struct.green) + 11 (pixel.bpp24_struct.blue)) / 3; 12 } /* ends loop over j */ 13 if(pad != 0){ 14 fseek(fp, pad, SEEK_CUR); 15 } /* ends if pad 1= 0 */ 16 } /* ends loop over i */ 17 }
32位色彩深度轉灰度圖
1 void bpp322grayscale(long height, long width, FILE* fp, short** the_image, int pad) 2 { 3 union bpp32_union pixel; 4 5 printf("bpp32\n"); 6 for(int i=0; i<height; i++){ 7 for(int j=0; j<width; j++){ 8 fread(&pixel, 1, 4, fp); 9 the_image[i][j] = ((pixel.bpp32_struct.red) + 10 (pixel.bpp32_struct.green) + 11 (pixel.bpp32_struct.blue)) / 3; 12 } /* ends loop over j */ 13 if(pad != 0){ 14 fseek(fp, pad, SEEK_CUR); 15 } /* ends if pad 1= 0 */ 16 } /* ends loop over i */ 17 }