程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> BMP圖像的灰度化---C++實現

BMP圖像的灰度化---C++實現

編輯:C++入門知識

灰度圖的結構主要包括文件頭,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);

 

 

include<iostream>  
#include <Windows.h>  
 
using namespace std; 
 
 
void main() 
{ 
     
    FILE* stream=fopen("D:\\3.bmp","rb"); 
    if(stream==NULL) 
    { 
        cout<<"文件不存在"<<endl; 
        return; 
    } 
     
    int sizeFileHeader=sizeof(BITMAPFILEHEADER); 
    int sizeInfoHeader=sizeof(BITMAPINFOHEADER); 
     
    BITMAPFILEHEADER* bitmapFileHeader=new BITMAPFILEHEADER[sizeFileHeader+1]; 
     
    BITMAPINFOHEADER* bitmapInfoHeader=new BITMAPINFOHEADER[sizeInfoHeader+1]; 
     
    memset(bitmapFileHeader,0,sizeFileHeader+1); 
    memset(bitmapInfoHeader,0,sizeInfoHeader+1); 
    fread(bitmapFileHeader,sizeof(char),sizeFileHeader,stream); 
    fseek(stream,sizeFileHeader,0); 
    fread(bitmapInfoHeader,sizeof(char),sizeInfoHeader,stream); 
    int srcImageLineByteCount=(((bitmapInfoHeader->biWidth*24)+31)/32)*4; 
    int destImageLineByteCount=(((bitmapInfoHeader->biWidth)*8+31)/32)*4; 
 
    //************位圖信息頭**********************  
     
    BYTE** oldImageData=new BYTE*[bitmapInfoHeader->biHeight]; 
    for(int i=0;i<bitmapInfoHeader->biHeight;i++) 
    { 
        oldImageData[i]=new BYTE[srcImageLineByteCount+1]; 
        memset(oldImageData[i],0,srcImageLineByteCount+1); 
    } 
 
    //***********位圖數據***********************  
    fseek(stream,sizeFileHeader+sizeInfoHeader,0); 
    //讀取圖像數據  
    for(int i=0;i<bitmapInfoHeader->biHeight;i++) 
    { 
        for (int j=0;j<srcImageLineByteCount;j++) 
        { 
            fread(&oldImageData[i][j],sizeof(BYTE),1,stream); 
 
        } 
         
    } 
 
    fclose(stream); 
     
    //調色板  
    RGBQUAD* pRgbQuards=new RGBQUAD[256]; 
    for(int i=0;i<256;i++) 
    { 
        pRgbQuards[i].rgbBlue=i; 
        pRgbQuards[i].rgbRed=i; 
        pRgbQuards[i].rgbGreen=i; 
 
    } 
     
    //修改信息頭  
    bitmapInfoHeader->biBitCount=8; 
    bitmapInfoHeader->biSizeImage=(bitmapInfoHeader->biHeight)*destImageLineByteCount; 
 
    //修改文件頭  
    bitmapFileHeader->bfOffBits=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)*256; 
    bitmapFileHeader->bfSize=bitmapFileHeader->bfOffBits+bitmapInfoHeader->biSizeImage; 
     
 
    //寫數據  
     
    BYTE** newImageData=new BYTE*[bitmapInfoHeader->biHeight]; 
 
    for (int i=0;i<bitmapInfoHeader->biHeight;i++) 
    { 
        newImageData[i]=new BYTE[destImageLineByteCount]; 
    } 
 
    for(int i=0;i<bitmapInfoHeader->biHeight;i++) 
    { 
        for(int j=0;j<destImageLineByteCount;j++) 
        { 
            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); 
        } 
    } 
 
 
    //寫入文件 

#include<iostream>
#include <Windows.h>

using namespace std;


void main()
{
 
 FILE* stream=fopen("D:\\3.bmp","rb");
 if(stream==NULL)
 {
  cout<<"文件不存在"<<endl;
  return;
 }
 
 int sizeFileHeader=sizeof(BITMAPFILEHEADER);
 int sizeInfoHeader=sizeof(BITMAPINFOHEADER);
 
 BITMAPFILEHEADER* bitmapFileHeader=new BITMAPFILEHEADER[sizeFileHeader+1];
 
 BITMAPINFOHEADER* bitmapInfoHeader=new BITMAPINFOHEADER[sizeInfoHeader+1];
 
 memset(bitmapFileHeader,0,sizeFileHeader+1);
 memset(bitmapInfoHeader,0,sizeInfoHeader+1);
 fread(bitmapFileHeader,sizeof(char),sizeFileHeader,stream);
 fseek(stream,sizeFileHeader,0);
 fread(bitmapInfoHeader,sizeof(char),sizeInfoHeader,stream);
 int srcImageLineByteCount=(((bitmapInfoHeader->biWidth*24)+31)/32)*4;
 int destImageLineByteCount=(((bitmapInfoHeader->biWidth)*8+31)/32)*4;

 //************位圖信息頭**********************
 
 BYTE** oldImageData=new BYTE*[bitmapInfoHeader->biHeight];
 for(int i=0;i<bitmapInfoHeader->biHeight;i++)
 {
  oldImageData[i]=new BYTE[srcImageLineByteCount+1];
  memset(oldImageData[i],0,srcImageLineByteCount+1);
 }

 //***********位圖數據***********************
 fseek(stream,sizeFileHeader+sizeInfoHeader,0);
 //讀取圖像數據
 for(int i=0;i<bitmapInfoHeader->biHeight;i++)
 {
  for (int j=0;j<srcImageLineByteCount;j++)
  {
   fread(&oldImageData[i][j],sizeof(BYTE),1,stream);

  }
  
 }

 fclose(stream);
 
 //調色板
 RGBQUAD* pRgbQuards=new RGBQUAD[256];
 for(int i=0;i<256;i++)
 {
  pRgbQuards[i].rgbBlue=i;
  pRgbQuards[i].rgbRed=i;
  pRgbQuards[i].rgbGreen=i;

 }
 
 //修改信息頭
 bitmapInfoHeader->biBitCount=8;
 bitmapInfoHeader->biSizeImage=(bitmapInfoHeader->biHeight)*destImageLineByteCount;

 //修改文件頭
 bitmapFileHeader->bfOffBits=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)*256;
 bitmapFileHeader->bfSize=bitmapFileHeader->bfOffBits+bitmapInfoHeader->biSizeImage;
 

 //寫數據
 
 BYTE** newImageData=new BYTE*[bitmapInfoHeader->biHeight];

 for (int i=0;i<bitmapInfoHeader->biHeight;i++)
 {
  newImageData[i]=new BYTE[destImageLineByteCount];
 }

 for(int i=0;i<bitmapInfoHeader->biHeight;i++)
 {
  for(int j=0;j<destImageLineByteCount;j++)
  {
   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);
  }
 }


 //寫入文件[cpp] view plaincopyprint?FILE* fileWrite=fopen("D:\\6.bmp","a+"); 
fwrite(bitmapFileHeader,sizeof(char),sizeof(BITMAPFILEHEADER),fileWrite); 
fwrite(bitmapInfoHeader,sizeof(char),sizeof(BITMAPINFOHEADER),fileWrite); 
fwrite(pRgbQuards,sizeof(RGBQUAD),256,fileWrite); 
 
for(int i=0;i<bitmapInfoHeader->biHeight;i++) 
{ 
    for(int j=0;j<destImageLineByteCount;j++) 
    { 
        fwrite(&newImageData[i][j],sizeof(BYTE),1,fileWrite); 
    } 
 
} 
fclose(fileWrite); 
 
cout<<"success"<<endl; 

 FILE* fileWrite=fopen("D:\\6.bmp","a+");
 fwrite(bitmapFileHeader,sizeof(char),sizeof(BITMAPFILEHEADER),fileWrite);
 fwrite(bitmapInfoHeader,sizeof(char),sizeof(BITMAPINFOHEADER),fileWrite);
 fwrite(pRgbQuards,sizeof(RGBQUAD),256,fileWrite);
 
 for(int i=0;i<bitmapInfoHeader->biHeight;i++)
 {
  for(int j=0;j<destImageLineByteCount;j++)
  {
   fwrite(&newImageData[i][j],sizeof(BYTE),1,fileWrite);
  }

 }
 fclose(fileWrite);

 cout<<"success"<<endl;
}

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


提醒:這裡沒有進行指針的釋放。。。

這兩行其實也可以用上一篇文章的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++實現文章中都說的差不多了,如果還有不明白的可以留言。。

效果如下:

原圖像:

 

 

\

灰度圖像:


 

\

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved