24位真色位图转化为8位灰度位图


位图文件(bitmap file)保存顺序如下:

位图头文件(BITMAPFILEHEADER)

位图信息头文件(BITMAPINFOHEADER

调色板RGBQUAD(真彩色位图没有调色板)

图像数据

##释义1##位图头文件(BITMAPFILEHEADER):
  1. typedef struct tagBITMAPFILEHEADER
  2. { /*14 bytes BMP文件头数据结构含有BMP文件的类型、
  3.                                文件大小和位图起始位置等信息*/
  4.     WORD bfType; /*2,位图文件的类型,必须为BM(0-1字节)*/
  5.     DWORD bfSize; /*4,位图文件的大小,以字节为单位(2-5字节)*/
  6.     WORD bfReserved1; /*2,位图文件保留字,必须为0(6-7字节)*/
  7.     WORD bfReserved2; /*2,位图文件保留字,必须为0(6-7字节)*/
  8.     DWORD bfOffBits; /*4,位图数据的起始位置,以相对于位图(10-13字节) */
  9. }BITMAPFILEHEADER,*PBITMAPFILEHEADER;
##释义2##位图信息头文件(BITMAPINFOHEADER):

 

  1. typedef struct tagBITMAPINFOHEADER
  2. { /*40 bytes BMP位图信息头数据用于说明位图的尺寸等信息。*/
  3.     DWORD biSize; /*4,本结构所占用字节数(14-17字节) */
  4.     LONG biWidth; /*4,位图的宽度,以像素为单位(18-21字节)*/
  5.     LONG biHeight; /*4,位图的高度,以像素为单位(22-25字节) */
  6.     WORD biPlanes; /*2,目标设备的级别,必须为1(26-27字节) */
  7.     WORD biBitCount;/*2每个像素所需的位数,必须是1(双色),(28-29字节)
  8.                           4(16色),8(256色)或24(真彩色)之一 */
  9.     DWORD biCompression;/*4,位图压缩类型,必须是 0(不压缩),(30-33字节)
  10.                        1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)之一 */
  11.     DWORD biSizeImage; /*4,位图的大小,以字节为单位(34-37字节) */
  12.     LONG biXPelsPerMeter;/*4,位图水平分辨率,每米像素数(38-41字节) */
  13.     LONG biYPelsPerMeter; /*4,位图垂直分辨率,每米像素数(42-45字节) */
  14.     DWORD biClrUsed;/*4, 位图实际使用的颜色表中的颜色数(46-49字节) */
  15.     DWORD biClrImportant;/*4,位图显示过程中重要的颜色数(50-53字节) */
  16. } BITMAPINFOHEADER,*PBITMAPINFOHEADER;

##释义3##调色板RGBQUAD(真彩色位图没有调色板):

 

  1. typedef struct tagRGBQUAD
  2. { /*颜色表用于说明位图中的颜色,它有若干个表项
  3.                       ,每一个表项是一个RGBQUAD类型的结构,定义一种颜色。*/
  4.     BYTE rgbBlue; /*蓝色的亮度(值范围为0-255)*/
  5.     BYTE rgbGreen; /*绿色的亮度(值范围为0-255) */
  6.     BYTE rgbRed;/*红色的亮度(值范围为0-255)*/
  7.     BYTE rgbReserved; /*保留,必须为0 */
  8. }RGBQUAD;

##释义4##图像数据:

    对于用到调色板的位图,图像数据就是该像素颜色在调色板中的索引值。对于真彩色图像,图像数据就是实际的R、G、B值,一个像素由3个字节24位组成,第一个字节表示B,第二个字节表示G,第三个字节表示R。

    注意:BMP文件是从下到上、从左都右排列的。读文件时,最先读到的是图像的最下面一行的左边的第一个像素,最后读到的是最上面一行的最右一个像素。

rgbtogray.h文件:
*****************
  1. /* C语言读入图像 位图文件结构声明 */
  2. #ifndef BMP_H_INCLUDED
  3. #define BMP_H_INCLUDED


  4. typedef unsigned short WORD;//2*8=16
  5. typedef unsigned long DWORD;//4*8=32
  6. typedef long LONG;//4*8=32
  7. typedef unsigned char BYTE;//1*8=8

  8. #pragma pack(1)
  9. typedef struct tagBITMAPFILEHEADER
  10. { /*14 bytes BMP文件头数据结构含有BMP文件的类型、
  11.                                文件大小和位图起始位置等信息*/
  12.     WORD bfType; /*2,位图文件的类型,必须为BM(0-1字节)*/
  13.     DWORD bfSize; /*4,位图文件的大小,以字节为单位(2-5字节)*/
  14.     WORD bfReserved1; /*2,位图文件保留字,必须为0(6-7字节)*/
  15.     WORD bfReserved2; /*2,位图文件保留字,必须为0(6-7字节)*/
  16.     DWORD bfOffBits; /*4,位图数据的起始位置,以相对于位图(10-13字节) */
  17. }BITMAPFILEHEADER,*PBITMAPFILEHEADER;
  18. #pragma pack()

  19. #pragma pack(1)
  20. typedef struct tagBITMAPINFOHEADER
  21. { /*40 bytes BMP位图信息头数据用于说明位图的尺寸等信息。*/
  22.     DWORD biSize; /*4,本结构所占用字节数(14-17字节) */
  23.     LONG biWidth; /*4,位图的宽度,以像素为单位(18-21字节)*/
  24.     LONG biHeight; /*4,位图的高度,以像素为单位(22-25字节) */
  25.     WORD biPlanes; /*2,目标设备的级别,必须为1(26-27字节) */
  26.     WORD biBitCount;/*2每个像素所需的位数,必须是1(双色),(28-29字节)
  27.                           4(16色),8(256色)或24(真彩色)之一 */
  28.     DWORD biCompression;/*4,位图压缩类型,必须是 0(不压缩),(30-33字节)
  29.                        1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)之一 */
  30.     DWORD biSizeImage; /*4,位图的大小,以字节为单位(34-37字节) */
  31.     LONG biXPelsPerMeter;/*4,位图水平分辨率,每米像素数(38-41字节) */
  32.     LONG biYPelsPerMeter; /*4,位图垂直分辨率,每米像素数(42-45字节) */
  33.     DWORD biClrUsed;/*4, 位图实际使用的颜色表中的颜色数(46-49字节) */
  34.     DWORD biClrImportant;/*4,位图显示过程中重要的颜色数(50-53字节) */
  35. } BITMAPINFOHEADER,*PBITMAPINFOHEADER;
  36. #pragma pack()

  37. #pragma pack(1)
  38. typedef struct tagRGBQUAD
  39. { /*颜色表用于说明位图中的颜色,它有若干个表项
  40.                       ,每一个表项是一个RGBQUAD类型的结构,定义一种颜色。*/
  41.     BYTE rgbBlue; /*蓝色的亮度(值范围为0-255)*/
  42.     BYTE rgbGreen; /*绿色的亮度(值范围为0-255) */
  43.     BYTE rgbRed;/*红色的亮度(值范围为0-255)*/
  44.     BYTE rgbReserved; /*保留,必须为0 */
  45. }RGBQUAD;/*颜色表中RGBQUAD结构数据的个数有biBitCount来确定:
  46.    当biBitCount=1,4,8时,分别有2,16,256个表项;
  47.    当biBitCount=24时,没有颜色表项。*/
  48. #pragma pack()

  49. #pragma pack(1)
  50. typedef struct tagBITMAPIMAGE
  51. { /*位图信息头和颜色表组成位图信息*/
  52.     BITMAPFILEHEADER bmiHeader; /*位图信息头*/
  53.     RGBQUAD bmiColors[1]; /*颜色表*/
  54. }BITMAPIMAGE;
  55. #pragma pack()

  56. #endif
*********************************************************************************************
rgbtogray.h文件:
******************
  1. /*******************************************************************************/
  2. #include<stdio.h>
  3. #include<stdlib.h>
  4. #include<malloc.h>
  5. #include<string.h>
  6. /********************************************************************/
  7. //自定义的有关图像处理的头文件为rgbtogray.h

  8. //系统定义有关图像处理的头文件为windows.h

  9. //目前,引用系统的windows.h程序工作正常,但自己的头文件有问题,待改正!

  10. //最终实现引用自己的头文件rgbtogray.h

  11. //太棒了:头文件的问题终于解决了

  12.   //#include<windows.h>

  13. #include "rgbtogray.h"
  14. /********************************************************************/
  15. /*****************************************************************************/
  16. //全局变量声明

  17. FILE * fpSrcBmpfile;//定义文件指针,用于读入和存储图像文件

  18. FILE * fpDestBmpfile;

  19. /******************************************************************************/
  20. //程序子函数声明

  21. void GetBmpHeader(PBITMAPFILEHEADER, PBITMAPINFOHEADER);//获得位图的文件头和信息头

  22. void ChangeBmpHeader(PBITMAPFILEHEADER, PBITMAPINFOHEADER, WORD);//改变位图的文件头和信息头

  23. void SetBmpHeader(const PBITMAPFILEHEADER, const PBITMAPINFOHEADER);//将修改后的文件头和信息头存入新位图文件

  24. void SetRGBQUAD();//建立颜色板并存入灰度图文件中

  25. int RgbToGray();//24位真色图转化为8位灰度图的主要函数


  26. /******************************************************************************/
  27. //主函数框架,菜单!(方便调用其他程序,以便拓展)

  28. void main()
  29. {
  30.     int command=1;
  31.     while(command)//菜单选项,可拓展

  32.     {
  33.     printf("\n*****************************Image Processing Menu***************************\n");
  34.     printf("|--------1:RGB To GRAY transform!--------|\n");
  35.     printf("|--------0:End!---------|\n");
  36.     printf("*****************************************************************************\n");    
  37.     printf("Hint:Processor Number?\n");
  38.     scanf("%d",&command);
  39.         switch(command)
  40.         {
  41.         case 1:
  42.             RgbToGray();
  43.             break;
  44.         case 0:
  45.             printf("---Bye-bye---\n");
  46.             break;
  47.         default:
  48.             printf("---Not defined number!\n");
  49.             break;
  50.         }    
  51.     }
  52. }

  53. /******************************************************************************/
  54. //函数体部分(副)

  55. void GetBmpHeader(PBITMAPFILEHEADER pbfheader, PBITMAPINFOHEADER pbiheader)
  56. {
  57.     fread(pbfheader, sizeof(BITMAPFILEHEADER), 1,fpSrcBmpfile);
  58.     fread(pbiheader, sizeof(BITMAPINFOHEADER), 1,fpSrcBmpfile);
  59. }
  60. void ChangeBmpHeader(PBITMAPFILEHEADER pbfheader, PBITMAPINFOHEADER pbiheader, WORD wType)
  61. {
  62.     pbiheader->biBitCount = wType; // 24 或者 8

  63.     pbiheader->biClrUsed = (wType == 24) ? 0 : 256;
  64.     pbfheader->bfOffBits = 54 + pbiheader->biClrUsed * sizeof(RGBQUAD);
  65.     pbiheader->biSizeImage = ((((pbiheader->biWidth * pbiheader->biBitCount) + 31) & ~31) / 8) * pbiheader->biHeight;
  66.     pbfheader->bfSize = pbfheader->bfOffBits + pbiheader->biSizeImage;
  67. }
  68. void SetBmpHeader(const PBITMAPFILEHEADER pbfheader, const PBITMAPINFOHEADER pbiheader)
  69. {
  70.     fwrite(pbfheader, sizeof(BITMAPFILEHEADER), 1, fpDestBmpfile);
  71.     fwrite(pbiheader, sizeof(BITMAPINFOHEADER), 1, fpDestBmpfile);
  72. }
  73. void SetRGBQUAD()
  74. {
  75.     int i;
  76.     RGBQUAD rgbquad[256];
  77.     for(i=0;i<256;i++) {
  78.         rgbquad[i].rgbBlue = i;
  79.         rgbquad[i].rgbGreen = i;
  80.         rgbquad[i].rgbRed = i;
  81.         rgbquad[i].rgbReserved = 0;
  82.     }
  83.     fwrite(rgbquad, 256 * sizeof(RGBQUAD), 1, fpDestBmpfile);
  84. }
  85. /******************************************************************************/
  86. //函数体部分(主)

  87. int RgbToGray()
  88. {
  89.     LONG w,h;
  90.     BYTE r,g,b;
  91.     BYTE gray;
  92.     BYTE count24,count8;
  93.     BYTE Bmpnul=0;

  94.     char SrcBmpfile[256];
  95.     char DestBmpfile[256];
  96.     
  97.     BITMAPFILEHEADER bmfh; // bmp文件头

  98.     BITMAPINFOHEADER bmih; // 位图信息头

  99.     BYTE *data;

  100.     memset(&bmfh, 0, sizeof(BITMAPFILEHEADER));//内存初始化

  101.     memset(&bmih, 0, sizeof(BITMAPINFOHEADER));
  102.     data=(BYTE *)malloc(3*sizeof(BYTE));
  103.     if(!data)
  104.         {
  105.            printf("Error:Can not allocate memory .\n");
  106.            free(data);
  107.            return -1;
  108.         }

  109.     getchar();
  110.     printf("Input the path of SrcBmpfile:\n");
  111.     gets(SrcBmpfile);

  112.     if((fpSrcBmpfile=fopen(SrcBmpfile,"rb"))==NULL) 
  113.     {
  114.         printf("Error:Open the file of SrcBmpfile failed!\n");//输入源位图文件

  115.         free(data);
  116.         return -1;
  117.     }
  118.     
  119.     rewind(fpSrcBmpfile);
  120.     GetBmpHeader(&bmfh,&bmih);
  121. //ceshie_start

  122.     printf("The contents in the file header of the BMP file:\n");
  123.     printf("bfType:%ld\n",bmfh.bfType);
  124.     printf("bfSize:%ld\n",bmfh.bfSize);
  125.     printf("bfReserved1:%ld\n",bmfh.bfReserved1);
  126.     printf("bfReserved2:%ld\n",bmfh.bfReserved2);
  127.     printf("bfOffBits:%ld\n",bmfh.bfOffBits);
  128.     printf("The contents in the info header:\n");
  129.     printf("biSize:%ld\n",bmih.biSize);
  130. //ceshi_end

  131.     if(bmfh.bfType!=0x4D42)
  132.     {
  133.         printf("Error:This file is not bitmap file!\n");
  134.         free(data);
  135.         return -1;
  136.     }
  137.     if(bmih.biBitCount!=24)
  138.     {
  139.         printf("Error:This bmpfile is not 24bit bitmap!\n");
  140.         free(data);
  141.         return -1;
  142.     }
  143.     if(bmih.biCompression!=0)
  144.     {
  145.         printf("Error:This 8bit bitmap file is not BI_RGB type!\n");
  146.         free(data);
  147.         return -1;
  148.     }

  149.     printf("Input the path of the DestBmpfile:\n");//输入目标位图文件

  150.     gets(DestBmpfile);

  151.     if((fpDestBmpfile=fopen(DestBmpfile,"wb"))==NULL)
  152.     {
  153.         printf("Error:Open the file of DestBmpfile failed!\n");
  154.         free(data);
  155.         return -1;
  156.     }

  157.     ChangeBmpHeader(&bmfh,&bmih,8);
  158.     SetBmpHeader(&bmfh,&bmih);
  159.     SetRGBQUAD();

  160.     count24=(4-(bmih.biWidth*3)%4)%4;
  161.     count8=(4-(bmih.biWidth)%4)%4;

  162.     for(h=bmih.biHeight-1;h>=0;h--)
  163.     {
  164.         for(w=0;w<bmih.biWidth;w++)
  165.         {
  166.             fread(data,3,1,fpSrcBmpfile);
  167.             if(feof(fpSrcBmpfile))
  168.             {
  169.                 printf("Error:Read Pixel data failed!\n");
  170.                 free(data);
  171.                 return -1;
  172.             }
  173.             b=*data;
  174.             g=*(data+1);
  175.             r=*(data+2);
  176.             gray=(299*r+587*g+114*b)/1000;
  177.             //if(gray>120)gray=250;

  178.             fwrite(&gray,sizeof(gray),1,fpDestBmpfile);
  179.         }
  180.         fseek(fpSrcBmpfile,count24,SEEK_CUR);
  181.         fwrite(&Bmpnul,1,count8,fpDestBmpfile);
  182.     }
  183.     printf("Hint:Convert RGB To GRAY Successfully!\n");
  184.     free(data);//释放内存空间

  185.     
  186.     fclose(fpDestBmpfile);//关闭文件指针

  187.     fclose(fpSrcBmpfile);
  188.     return 0;
  189. }
  190. /******************************************************************************/
*******************************************************************************************
#prama pack(n)
结构体定义;
#prama pack()
##释义##:关于struct的使用方法:
     struct是一种复合数据类型,其构成元素既可以是基本数据类型(如int、long、float等)的变量,也可以是一些复合数据类型(如array、struct、union等)的数据单元。对于结构体,编译器会自动进行成员变量的对齐,以提高运算效率。缺省情况下,编译器为结构体的每个成员按其自然对界(natural alignment)条件分配空间。各个成员按照它们被声明的顺序在内存中顺序存储,第一个成员的地址和整个结构的地址相同。
    自然对界是指按结构体的成员中size最大的成员对齐。
#pragma pack规定的对齐长度,实际使用的规则是:
    结构,联合,或者类的数据成员,第一个放在偏移为0的地方,以后每个数据成员的对齐,按照#pragma pack指定的数值和结构体的自然对齐长度中比较小的那个进行。
    也就是说,当#pragma pack的值等于或超过所有数据成员长度的时候,这个值的大小将不产生任何效果。
    结构体的对齐,按照结构体中size最大的数据成员和#pragma pack指定值之间,较小的那个进行。
 
*******************************************************************************************
参考资料:
书目:《Visual C++实用图像处理》;
网站: www.cprogramming.com(解决了结构体定义的相关问题 ,即 #prama pack)

 
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值