bmp图像灰色化

灰度图的结构主要包括文件头,BMP信息头,调色板,BMP数据内容四部分。灰度图的调色板共有256项RGBQUAD结构,存放0到255的灰度值,每一项rgbRed、rgbGreen、rgbBlue分量值相等。

参考文章:BMP图像的结构及读写和灰度化
24位真彩BMP图像的灰度化
      把24位真彩BMP图像转变成256阶灰度图的具体步骤如下:
(1) 修改信息头
       信息头共有11部分,灰度化时需要修改两部分
bi2.biBitCount=8;
bi2.biSizeImage=( (bi.biWidth+3)/4 ) * 4*bi.biHeight;

(2)修改文件头
       文件头共有5部分,灰度化时需要修改两部分
          bf2.bfOffBits = sizeof(bf2)+sizeof(BITMAPINFOHEADER)+256*sizeof(RGBQUAD);
bf2.bfSize = bf2.bfOffBits + bi2.biSizeImage;


(3)创建调色板
RGBQUAD *ipRGB2 = (RGBQUAD *)malloc(256*sizeof(RGBQUAD));
for ( i = 0; i < 256; i++ )
ipRGB2[i].rgbRed = ipRGB2[i].rgbGreen = ipRGB2[i].rgbBlue = i;


(4)修改位图数据部分
         这部分主要是由原真彩图的rgbRed、rgbGreen、rgbBlue分量值得到灰度图像的灰度值Y,

可以用下面公式得到:
            Y=0.299*rgbRed+0.587* rgbGreen+0.114*rgbBlue;
具体修改代码如下:
int nBytesPerLine2 = ( (bi.biWidth+3)/4 ) * 4;
nLineStart2 = nBytesPerLine2 * i;
for ( int j = 0; j<nBytesPerLine2;j++ )
ImgData2[nLineStart2+j]= int( (float)Imgdata[i][3 * j] * 0.114 + \
(float)Imgdata[i][3 * j + 1] * 0.587 + \
(float)Imgdata[i][3 * j + 2] * 0.299 );//用一个一维数组顺序存储灰度值


(5)按顺序写入BMP图像的各个部分
          fwrite(&bf2,sizeof(BITMAPFILEHEADER),1,fp); 
fwrite(&bi2,sizeof(BITMAPINFOHEADER),1,fp);
fwrite(ipRGB2,sizeof(RGBQUAD),256,fp);
fwrite(ImgData2,nImageSize2,1,fp);

  1. #include<iostream>  
  2. #include <Windows.h>  
  3.   
  4. using namespace std;  
  5.   
  6.   
  7. void main()  
  8. {  
  9.       
  10.     FILE* stream=fopen("D:\\3.bmp","rb");  
  11.     if(stream==NULL)  
  12.     {  
  13.         cout<<"文件不存在"<<endl;  
  14.         return;  
  15.     }  
  16.       
  17.     int sizeFileHeader=sizeof(BITMAPFILEHEADER);  
  18.     int sizeInfoHeader=sizeof(BITMAPINFOHEADER);  
  19.       
  20.     BITMAPFILEHEADER* bitmapFileHeader=new BITMAPFILEHEADER[sizeFileHeader+1];  
  21.       
  22.     BITMAPINFOHEADER* bitmapInfoHeader=new BITMAPINFOHEADER[sizeInfoHeader+1];  
  23.       
  24.     memset(bitmapFileHeader,0,sizeFileHeader+1);  
  25.     memset(bitmapInfoHeader,0,sizeInfoHeader+1);  
  26.     fread(bitmapFileHeader,sizeof(char),sizeFileHeader,stream);  
  27.     fseek(stream,sizeFileHeader,0);  
  28.     fread(bitmapInfoHeader,sizeof(char),sizeInfoHeader,stream);  
  29.     int srcImageLineByteCount=(((bitmapInfoHeader->biWidth*24)+31)/32)*4;  
  30.     int destImageLineByteCount=(((bitmapInfoHeader->biWidth)*8+31)/32)*4;  
  31.   
  32.     //************位图信息头**********************  
  33.       
  34.     BYTE** oldImageData=new BYTE*[bitmapInfoHeader->biHeight];  
  35.     for(int i=0;i<bitmapInfoHeader->biHeight;i++)  
  36.     {  
  37.         oldImageData[i]=new BYTE[srcImageLineByteCount+1];  
  38.         memset(oldImageData[i],0,srcImageLineByteCount+1);  
  39.     }  
  40.   
  41.     //***********位图数据***********************  
  42.     fseek(stream,sizeFileHeader+sizeInfoHeader,0);  
  43.     //读取图像数据  
  44.     for(int i=0;i<bitmapInfoHeader->biHeight;i++)  
  45.     {  
  46.         for (int j=0;j<srcImageLineByteCount;j++)  
  47.         {  
  48.             fread(&oldImageData[i][j],sizeof(BYTE),1,stream);  
  49.   
  50.         }  
  51.           
  52.     }  
  53.   
  54.     fclose(stream);  
  55.       
  56.     //调色板  
  57.     RGBQUAD* pRgbQuards=new RGBQUAD[256];  
  58.     for(int i=0;i<256;i++)  
  59.     {  
  60.         pRgbQuards[i].rgbBlue=i;  
  61.         pRgbQuards[i].rgbRed=i;  
  62.         pRgbQuards[i].rgbGreen=i;  
  63.   
  64.     }  
  65.       
  66.     //修改信息头  
  67.     bitmapInfoHeader->biBitCount=8;  
  68.     bitmapInfoHeader->biSizeImage=(bitmapInfoHeader->biHeight)*destImageLineByteCount;  
  69.   
  70.     //修改文件头  
  71.     bitmapFileHeader->bfOffBits=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)*256;  
  72.     bitmapFileHeader->bfSize=bitmapFileHeader->bfOffBits+bitmapInfoHeader->biSizeImage;  
  73.       
  74.   
  75.     //写数据  
  76.       
  77.     BYTE** newImageData=new BYTE*[bitmapInfoHeader->biHeight];  
  78.   
  79.     for (int i=0;i<bitmapInfoHeader->biHeight;i++)  
  80.     {  
  81.         newImageData[i]=new BYTE[destImageLineByteCount];  
  82.     }  
  83.   
  84.     for(int i=0;i<bitmapInfoHeader->biHeight;i++)  
  85.     {  
  86.         for(int j=0;j<destImageLineByteCount;j++)  
  87.         {  
  88.             newImageData[i][j]=(int)((float)oldImageData[i][j*3]*0.114+  
  89.                 (float)oldImageData[i][j*3+1]*0.587+(float)oldImageData[i][3*j+2]*0.299);  
  90.         }  
  91.     }  
  92.   
  93.   
  94.     //写入文件  
  1. FILE* fileWrite=fopen("D:\\6.bmp","a+");  
  2. fwrite(bitmapFileHeader,sizeof(char),sizeof(BITMAPFILEHEADER),fileWrite);  
  3. fwrite(bitmapInfoHeader,sizeof(char),sizeof(BITMAPINFOHEADER),fileWrite);  
  4. fwrite(pRgbQuards,sizeof(RGBQUAD),256,fileWrite);  
  5.   
  6. for(int i=0;i<bitmapInfoHeader->biHeight;i++)  
  7. {  
  8.     for(int j=0;j<destImageLineByteCount;j++)  
  9.     {  
  10.         fwrite(&newImageData[i][j],sizeof(BYTE),1,fileWrite);  
  11.     }  
  12.   
  13. }  
  14. fclose(fileWrite);  
  15.   
  16. cout<<"success"<<endl;  

 

 int srcImageLineByteCount=(((bitmapInfoHeader->biWidth*24)+31)/32)*4;
 int destImageLineByteCount=(((bitmapInfoHeader->biWidth)*8+31)/32)*4;

提醒:这里没有进行指针的释放。。。

扫描二维码关注公众号,回复: 1983111 查看本文章

这两行其实也可以用上一篇文章的WIDTHBYTES(bitmapInfoHeader->biWidth*24)和WIDTHBYTES(bitmapInfoHeader->biWidth*8)

有些地方也用( (bi.biWidth+3)/4 ) * 4和((bi.biWidth*3+3)/4)*4这样的表达式。。原理都是一样的。其实( (bi.biWidth+3)/4 ) * 4写成( (bi.biWidth*1+3)/4 ) * 4估计会好理解吧。。

因为BMP图像每个像素都是有三个RGB分量组成(24位,32位也就是多了个Alpha),而在灰度图像中每个像素只是一个灰度值,从代码:newImageData[i][j]=(int)((float)oldImageData[i][j*3]*0.114+(float)oldImageData[i][j*3+1]*0.587+(float)oldImageData[i][3*j+2]*0.299); 可看出,每个灰度值都是由原来的彩色图像的每个RGB分量通过一定的公式计算得来的。因此灰度图像和原来的彩色图像虽然在宽度和高度(像素单位)是一样的,但是因为组成不同,所以每行的字节数就是不一样的。。

至于其他的就不多说了,在前面WIDTHBYTES位图操作函数详解BMP文件读写复习---C++实现文章中都说的差不多了,如果还有不明白的可以留言。

猜你喜欢

转载自blog.csdn.net/wyyy2088511/article/details/80192499