C語(yǔ)言實(shí)現(xiàn)BMP圖像處理(彩色圖轉(zhuǎn)灰度圖)
我們知道真彩圖不帶調(diào)色板,每個(gè)象素用 3 個(gè)字節(jié),表示 R、G、B 三個(gè)分量。所以處理很簡(jiǎn)單,根據(jù) R、G、B 的值求出 Y 值后,將 R、G、B 值都賦值成 Y,寫入新圖即可。 在YUV 的顏色表示方法中,Y 分量的物理含義就是亮度,它含了灰度圖(grayscale)的所有信息,只用 Y 分量就完全能夠表示出一幅灰度圖來(lái)。YUV 和RGB 之間有著如下的對(duì)應(yīng)關(guān)系:

再來(lái)看看帶調(diào)色板的彩色圖,我們知道位圖中的數(shù)據(jù)只是對(duì)應(yīng)調(diào)色板中的一個(gè)索引值,我們只需要將調(diào)色板中的彩色變成灰度,形成新調(diào)色板,而位圖數(shù)據(jù)不用動(dòng),就可以了。
以上解釋來(lái)自于:《數(shù)字圖像處理編程入門》,代碼參考:C語(yǔ)言實(shí)現(xiàn)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;//保證每一行字節(jié)數(shù)都為4的整數(shù)倍
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;
//修改文件頭,其中有兩項(xiàng)需要修改,分別為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);//修改偏移字節(jié)數(shù)
fwrite(&bfhead, 14, 1, fp1); //將修改后的文件頭存入fp1;
//修改信息頭,其中有兩項(xiàng)需要修改,1個(gè)位biBitCount:真彩圖為24 ,應(yīng)改成8;另一個(gè)是biSizeImage:由于每像素所占位數(shù)的變化,所以位圖數(shù)據(jù)的大小發(fā)生變化
BITMAPINFOHEADER head1;
head1.biBitCount = 8; //將每像素的位數(shù)改為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;//修改位圖數(shù)據(jù)的大小
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;
//寫位圖數(shù)據(jù)
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; //將每一個(gè)像素都按公式y(tǒng)=B*0.299+G*0.587+R*0.114進(jìn)行轉(zhuǎn)化
pb2 = pBmpBuf1 + i*LineByte1 + j;
*pb2 = y;
}
}
fwrite(pBmpBuf1, LineByte1*bmpHeight, 1, fp1);
fclose(fp1);
system("pause");
return 0;
}
實(shí)驗(yàn)結(jié)果分析:

實(shí)驗(yàn)結(jié)果分析:真彩色圖不帶調(diào)色板,而灰度圖的調(diào)色板為256級(jí)。所以在修改調(diào)色板時(shí)需要將RGB三個(gè)分量修改為256級(jí),根據(jù)YUV顏色空間中Y分量計(jì)算。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
C語(yǔ)言數(shù)據(jù)結(jié)構(gòu)算法之實(shí)現(xiàn)快速傅立葉變換
這篇文章主要介紹了C語(yǔ)言數(shù)據(jù)結(jié)構(gòu)算法之實(shí)現(xiàn)快速傅立葉變換的相關(guān)資料,需要的朋友可以參考下2017-06-06
C語(yǔ)言實(shí)現(xiàn)掃雷小游戲的全過(guò)程記錄
這篇文章主要給大家介紹了關(guān)于C語(yǔ)言實(shí)現(xiàn)掃雷小游戲的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04
C語(yǔ)言完整實(shí)現(xiàn)12種排序算法(小結(jié))
本文主要介紹了C語(yǔ)言完整實(shí)現(xiàn)12種排序算法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-05-05
C語(yǔ)言的數(shù)字游戲算法效率問(wèn)題探討實(shí)例
這篇文章主要介紹了C語(yǔ)言的數(shù)字游戲算法效率問(wèn)題探討實(shí)例,需要的朋友可以參考下2014-04-04

