c語言數字圖像處理(一):bmp圖片格式及灰度圖片轉換

本篇文章首先介紹了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 字節app

bpp = 4 調色板 16 * 4 字節oop

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.this

<https://en.wikipedia.org/wiki/BMP_file_format>spa

調色板數據格式 [blue][green][red][alpha = 0x00]3d

 

 位圖格式分析

1bpp(單色位圖)        code

 

4bpp(16色位圖)orm

 

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 }
相關文章
相關標籤/搜索