C語言實現(xiàn)BMP圖像處理(彩色圖轉(zhuǎn)灰度圖)
我們知道真彩圖不帶調(diào)色板,每個象素用 3 個字節(jié),表示 R、G、B 三個分量。所以處理很簡單,根據(jù) R、G、B 的值求出 Y 值后,將 R、G、B 值都賦值成 Y,寫入新圖即可。 在YUV 的顏色表示方法中,Y 分量的物理含義就是亮度,它含了灰度圖(grayscale)的所有信息,只用 Y 分量就完全能夠表示出一幅灰度圖來。YUV 和RGB 之間有著如下的對應(yīng)關(guān)系:
再來看看帶調(diào)色板的彩色圖,我們知道位圖中的數(shù)據(jù)只是對應(yīng)調(diào)色板中的一個索引值,我們只需要將調(diào)色板中的彩色變成灰度,形成新調(diào)色板,而位圖數(shù)據(jù)不用動,就可以了。
以上解釋來自于:《數(shù)字圖像處理編程入門》,代碼參考:C語言實現(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; //修改文件頭,其中有兩項需要修改,分別為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; //修改信息頭,其中有兩項需要修改,1個位biBitCount:真彩圖為24 ,應(yīng)改成8;另一個是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; //將每一個像素都按公式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; }
實驗結(jié)果分析:
實驗結(jié)果分析:真彩色圖不帶調(diào)色板,而灰度圖的調(diào)色板為256級。所以在修改調(diào)色板時需要將RGB三個分量修改為256級,根據(jù)YUV顏色空間中Y分量計算。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
一文詳解C++子類函數(shù)為什么不能重載父類函數(shù)
這篇文章主要介紹了一文詳解C++子類函數(shù)為什么不能重載父類函數(shù),文章圍繞主題展開詳細(xì)的內(nèi)容戒殺,具有一定的參考價值,需要的朋友可以參考一下2022-09-09C++實現(xiàn)LeetCode(129.求根到葉節(jié)點數(shù)字之和)
這篇文章主要介紹了C++實現(xiàn)LeetCode(129.求根到葉節(jié)點數(shù)字之和),本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07C語言數(shù)據(jù)結(jié)構(gòu)之串插入操作
這篇文章主要介紹了C語言數(shù)據(jù)結(jié)構(gòu)之串插入操作的相關(guān)資料,希望通過本文能幫助到大家,讓大家實現(xiàn)這樣的功能,需要的朋友可以參考下2017-10-10