C語言實現BMP圖像處理(彩色圖轉灰度圖)

我們知道真彩圖不帶調色板,每個象素用 3 個字節,表示 R、G、B 三個分量。所以處理很簡單,根據 R、G、B 的值求出 Y 值後,將 R、G、B 值都賦值成 Y,寫入新圖即可。 在YUV 的顏色表示方法中,Y 分量的物理含義就是亮度,它含瞭灰度圖(grayscale)的所有信息,隻用 Y 分量就完全能夠表示出一幅灰度圖來。YUV 和RGB 之間有著如下的對應關系:

再來看看帶調色板的彩色圖,我們知道位圖中的數據隻是對應調色板中的一個索引值,我們隻需要將調色板中的彩色變成灰度,形成新調色板,而位圖數據不用動,就可以瞭。

以上解釋來自於:《數字圖像處理編程入門》,代碼參考:C語言實現24位彩色圖像二值化

#include<stdio.h>
#include<windows.h>
 
int main(int argc, char* argv[])
{
 int bmpHeight;
 int bmpWidth;
 unsigned char *pBmpBuf;
 RGBQUAD *pColorTable;
 int biBitCount;
 
 //讀取bmp文件
 FILE *fp = fopen("./02.bmp", "rb");
 if (fp == 0)
  return 0;
 fseek(fp, sizeof(BITMAPFILEHEADER), 0);
 
 BITMAPINFOHEADER head;
 fread(&head, 40, 1, fp);
 bmpHeight = head.biHeight;
 bmpWidth = head.biWidth;
 biBitCount = head.biBitCount;
 
 fseek(fp, sizeof(RGBQUAD), 1);
 
 int LineByte = (bmpWidth*biBitCount / 8 + 3) / 4 * 4;//保證每一行字節數都為4的整數倍
 pBmpBuf = new unsigned char[LineByte*bmpHeight];
 fread(pBmpBuf, LineByte*bmpHeight, 1, fp);
 fclose(fp);
 
 //將24位真彩圖灰度化並保存
 FILE *fp1 = fopen("gray.bmp", "wb");
 if (fp1 == 0)
  return 0;
 int LineByte1 = (bmpWidth * 8 / 8 + 3) / 4 * 4;
 
 //修改文件頭,其中有兩項需要修改,分別為bfSize和bfOffBits
 BITMAPFILEHEADER bfhead;
 bfhead.bfType = 0x4D42;
 bfhead.bfSize = 14 + 40 + 256 * sizeof(RGBQUAD)+LineByte1*bmpHeight;//修改文件大小
 bfhead.bfReserved1 = 0;
 bfhead.bfReserved2 = 0;
 bfhead.bfOffBits = 14 + 40 + 256 * sizeof(RGBQUAD);//修改偏移字節數
 fwrite(&bfhead, 14, 1, fp1);    //將修改後的文件頭存入fp1;
 
 //修改信息頭,其中有兩項需要修改,1個位biBitCount:真彩圖為24 ,應改成8;另一個是biSizeImage:由於每像素所占位數的變化,所以位圖數據的大小發生變化
 BITMAPINFOHEADER head1;
 head1.biBitCount = 8;    //將每像素的位數改為8
 head1.biClrImportant = 0;
 head1.biCompression = 0;
 head1.biClrUsed = 0;
 head1.biHeight = bmpHeight;
 head1.biWidth = bmpWidth;
 head1.biPlanes = 1;
 head1.biSize = 40;
 head1.biSizeImage = LineByte1*bmpHeight;//修改位圖數據的大小
 head1.biXPelsPerMeter = 0;
 head1.biYPelsPerMeter = 0;
 fwrite(&head1, 40, 1, fp1);  //將修改後的信息頭存入fp1;
 
 pColorTable = new RGBQUAD[256];
 for (int i = 0; i < 256; i++){
  pColorTable[i].rgbRed = i;
  pColorTable[i].rgbGreen = i;
  pColorTable[i].rgbBlue = i; //是顏色表裡的B、G、R分量都相等,且等於索引值
 }
 fwrite(pColorTable, sizeof(RGBQUAD), 256, fp1); //將顏色表寫入fp1;
 
 //寫位圖數據
 unsigned char *pBmpBuf1;
 pBmpBuf1 = new unsigned char[LineByte1*bmpHeight];
 for (int i = 0; i < bmpHeight; i++){
  for (int j = 0; j<bmpWidth; j++){
   unsigned char *pb1, *pb2;
   pb1 = pBmpBuf + i*LineByte + j * 3;
   int y = *(pb1)*0.299 + *(pb1 + 1)*0.587 + *(pb1 + 2)*0.114;   //將每一個像素都按公式y=B*0.299+G*0.587+R*0.114進行轉化
   pb2 = pBmpBuf1 + i*LineByte1 + j;
   *pb2 = y;
  }
 }
 fwrite(pBmpBuf1, LineByte1*bmpHeight, 1, fp1);
 
 fclose(fp1);
 
 system("pause");
 return 0;
}

實驗結果分析:

實驗結果分析:真彩色圖不帶調色板,而灰度圖的調色板為256級。所以在修改調色板時需要將RGB三個分量修改為256級,根據YUV顏色空間中Y分量計算。

以上就是本文的全部內容,希望對大傢的學習有所幫助,也希望大傢多多支持WalkonNet。

推薦閱讀: