1. 程式人生 > >24位點陣圖轉8位灰度圖

24位點陣圖轉8位灰度圖

如何用RGB轉化得到的灰度資料寫入8位bmp檔案,請看如下程式碼

其中lp中儲存的是已經轉化得到的現成灰度資料,標紅的程式碼是與24位點陣圖不同的地方。

<span style="font-size:18px;">//(整個點陣圖由檔案頭、資訊頭、調色盤、顏色表這四部分組合構成
	typedef long LONG;
	typedef unsigned long DWORD;
	typedef unsigned short WORD;
#pragma pack (push ,1)//由於4位元組對齊,而資訊頭大小為54位元組,第一部分14位元組,
	//第二部分40位元組,所以會將第一部分補齊為16自己,直接用sizeof,開啟圖片時就會
	//遇到premature end-of-file encountered錯誤
	typedef struct {//點陣圖檔案頭,14位元組
		WORD      bfType;   //  指定檔案型別,必須是0x424D,即字串“BM”,也就是說所有.bmp檔案的頭兩個位元組都是“BM”。
		DWORD   bfSize;   //   點陣圖檔案的大小,包括這14個位元組,以位元組為單位  
		WORD      bfReserved1;   //   點陣圖檔案保留字,必須為0
		WORD      bfReserved2;   //   點陣圖檔案保留字,必須為0
		DWORD   bfOffBits;   //   點陣圖資料的起始位置,以相對於點陣圖, 檔案頭的偏移量表示,以位元組為單位
	} BMPFILEHEADER_T;
#pragma pack (pop)
	typedef struct{//這個結構的長度是固定的,為40個位元組,可以自己算一下,DWORD、LONG4個位元組,WORD兩個位元組
		DWORD      biSize;//指定這個結構的長度,為40
		LONG       biWidth;//指定圖象的寬度,單位是象素。
		LONG       biHeight;//指定圖象的高度,單位是象素。
		WORD       biPlanes;//必須是1,不用考慮。
		WORD       biBitCount;/*指定表示顏色時要用到的位數,常用的值為1(黑白二色圖), 4(16色圖),
							  8(256色), 24(真彩色圖)(新的.bmp格式支援32位色,這裡就不做討論了)。*/
		DWORD      biCompression;/*指定點陣圖是否壓縮,有效的值為BI_RGB,BI_RLE8,BI_RLE4,
								 BI_BITFIELDS(都是一些Windows定義好的常量)。要說明的是,
								 Windows點陣圖可以採用RLE4,和RLE8的壓縮格式,但用的不多。
								 我們今後所討論的只有第一種不壓縮的情況,即biCompression為BI_RGB的情況。*/
		DWORD      biSizeImage;/*指定實際的點陣圖資料佔用的位元組數,其實也可以從以下的公式中計算出來:
biSizeImage=biWidth’ × biHeight
要注意的是:上述公式中的biWidth’必須是4的整倍數(所以不是biWidth,而是biWidth’,
表示大於或等於biWidth的,最接近4的整倍數。舉個例子,如果biWidth=240,則biWidth’=240;
如果biWidth=241,biWidth’=244)。如果biCompression為BI_RGB,則該項可能為零*/
		LONG       biXPelsPerMeter;//指定目標裝置的水平解析度,單位是每米的象素個數
		LONG       biYPelsPerMeter;//指定目標裝置的垂直解析度,單位同上。
		DWORD      biClrUsed;//指定本圖象實際用到的顏色數,如果該值為零,則用到的顏色數為2的biBitCount指數次冪
		DWORD      biClrImportant;//指定本圖象中重要的顏色數,如果該值為零,則認為所有的顏色都是重要的。
	} BMPINFOHEADER_T;


	char * bmp_file = "行人資料庫-負樣本99.bmp";//要儲存的bmp檔名,字尾不要忘了
	//int width = cx.GetWidth();
	//int height = cx.GetHeight();

	// 點陣圖第一部分,檔案資訊  
	BMPFILEHEADER_T bfh;
	int kk = sizeof(BMPFILEHEADER_T);//14,不對齊的話會得到16,這樣建立的BMP打不開
	int nn = sizeof(BMPINFOHEADER_T);// second section size,40
	bfh.bfType = (WORD)0x4d42;  //bm  
	//灰度影象8位深度
	int newbiBitCount = 8;
	//8點陣圖像資料每行位元組數為4的倍數
	int lineByte = (width * newbiBitCount / 8 + 3) / 4 * 4;
	//灰度圖有顏色表,顏色表大小,以位元組為單位,灰度影象顏色表為1024位元組,彩色影象顏色表大小為0
	int colorTablesize = 1024;
	<span style="color:#ff0000;">bfh.bfSize = kk + nn + colorTablesize + lineByte*height;</span>
	bfh.bfReserved1 = 0; // reserved  
	bfh.bfReserved2 = 0; // reserved  
	bfh.bfOffBits = sizeof(BMPFILEHEADER_T) + sizeof(BMPINFOHEADER_T);//真正的資料的位置  


	// 點陣圖第二部分,資料資訊  
	BMPINFOHEADER_T bih;
	bih.biSize = sizeof(BMPINFOHEADER_T);
	bih.biWidth = width;
	bih.biHeight = height;  
	bih.biPlanes = 1;//為1,不用改  
	<span style="color:#ff0000;">bih.biBitCount = newbiBitCount;</span>
	bih.biCompression = 0;//不壓縮  
	bih.biSizeImage = datalen;
	bih.biXPelsPerMeter = 0;
	bih.biYPelsPerMeter = 0;
	bih.biClrUsed = 0;
	bih.biClrImportant = 0;//每個畫素都重要  
	FILE * fp = fopen(bmp_file, "wb");//建立bmp檔案
	if (!fp) 
		return-1;
	fwrite(&bfh, 8, 1, fp);
	fwrite(&bfh.bfReserved2, sizeof(bfh.bfReserved2), 1, fp);
	fwrite(&bfh.bfOffBits, sizeof(bfh.bfOffBits), 1, fp);
	fwrite(&bih, sizeof(BMPINFOHEADER_T), 1, fp);

	//灰度影象,有顏色表,寫入檔案 
	RGBQUAD colortable[256];
	for (int i = 0; i<256; ++i)
	{
		colortable[i].rgbBlue = i;
		colortable[i].rgbGreen = i;
		colortable[i].rgbRed = i;
		colortable[i].rgbReserved = 0;
	}
	RGBQUAD* pColorTable1 = colortable;
	<span style="color:#ff0000;">fwrite(pColorTable1, sizeof(RGBQUAD), 256, fp);</span>
	//為新影象申請空間
	BYTE*ptempimageBuf = new unsigned char[lineByte*height];
	if (!ptempimageBuf)
		return -3;
	for (int i = 0; i<height; i++)   //color change from 24 to 8 bit
	{
		for (int j = 0, k = 0; j<width; j++)
		{
			ptempimageBuf[i*lineByte + j] = lp[i*width+j];
		}
	}
	//寫入rgb資料
	<span style="color:#ff0000;">fwrite(ptempimageBuf, lineByte*height, 1, fp);</span>
	fclose(fp);
	delete[]ptempimageBuf;</span>