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 字节

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 }

 

posted @ 2018-09-09 17:31  GoldBeetle  阅读(19234)  评论(9编辑  收藏  举报