C++——bmp画像の階調化+二値化


本稿では、bmp画像の階調化及び二値化操作を実現する.
1、階調化
カラーの階調を変えるには、有名な心理学の公式があります.
                          Gray = R*0.299 + G*0.587 + B*0.114
実際の応用では,低速の浮動小数点演算を避けることが望ましいため,整数アルゴリズムが必要である.係数はいずれも3ビット精度ではないことに気づき、1000倍にスケーリングして整数演算アルゴリズムを実現することができます:Gray=(R*299+G*587+B*114+500)/1000 RGBは一般的に8ビット精度で、現在は1000倍にスケーリングされているので、上記の演算は32ビット整数型の演算です.注意後の除算は整数除算なので、500を加えて四捨五入を実現する必要があります.このアルゴリズムには32ビット演算が必要であるため,この式のもう一つの変種が流行している:Gray=(R*30+G*59+B*11+50)/100
しかし、前の式は32ビット整数演算であったが、80 x 86系の整数乗算命令の特徴により、16ビット整数乗算命令で演算できるようになった.しかも現在32ビットが早く普及している(AMD 64が出ている)ので、前の式を使うことをお勧めします.
上の整数アルゴリズムはもう速いですが、速度を制約している点があります.最後の除算です.シフトは除算よりもずっと速いので、係数を2の整数べき乗にスケールすることができます.慣習的に16ビット精度を用い,2の16乗は65536であり,したがって,この計算係数は,0.299*65536=19595.264≒19595 0.587*65536+(0.264)=38469.632+0.264=38469.896≒38469 0.114*65536+(0.896)=7471.104+0.896=7472で多くの人が見たことがある.私が使っている捨て方は四捨五入ではありません.四捨五入会は大きな誤差があり、以前の計算結果の誤差を一緒に計算すべきで、端数処理は、端数処理法です.式は、Gray=(R*19595+G*38469+B*7472)>>16 2~20ビット精度の係数です.Gray=(R*1+G*2+B*1)>>2 Gray=(R*2+G*5+B*1)>>3 Gray=(R*4 + G*10 + B*2) >> 4                          Gray = (R*9 + G*19 + B*4) >> 5                          Gray = (R*19 + G*37 + B*8) >> 6                          Gray = (R*38 + G*75 + B*15) >> 7                          Gray = (R*76 + G*150 + B*30) >> 8                          Gray = (R*153 + G*300 + B*59) >> 9                          Gray = (R*306 + G*601 + B*117) >> 10                          Gray = (R*612 + G*1202 + B*234) >> 11                          Gray = (R*1224 + G*2405 + B*467) >> 12                          Gray = (R*2449 + G*4809 + B*934) >> 13                          Gray = (R*4898 + G*9618 + B*1868) >> 14                          Gray = (R*9797 + G*19235 + B*3736) >> 15                          Gray = (R*19595 + G*38469 + B*7472) >> 16                          Gray = (R*39190 + G*76939 + B*14943) >> 17                          Gray = (R*78381 + G*153878 + B*29885) >> 18                          Gray = (R*156762 + G*307757 + B*59769) >> 19
                          Gray = (R*313524 + G*615514 + B*119538) >> 20
階調化処理には多くの方法があり、本稿では1つだけを選択する.
2、二値化
画像の二値化処理は、画像上の点の階調を0または255にすることであり、すなわち、画像全体が明らかな白黒効果を示す.256個の輝度レベルの階調画像を適切なバルブ値選択により、画像全体と局所的特徴を依然として反映できる二値化画像を得る.すべての階調がバルブ値以上の画素は、特定の物体に属すると判定され、その階調値は255で表され、そうでなければ、これらの画素点は物体領域の外に排除され、階調値は0であり、背景または例外の物体領域を表す.
void img_rgb2gray()
{

	char readPath[] = "D:\\C++_file\\image_deal_C++\\IMAGE_JIEQU\\1.bmp";
	readBmp(readPath);

	
	unsigned char *pGrayData;
	//           ,     
	bfoffbits += (sizeof(RGBQUAD) * 256);
	//biSizeImg              ,             ,  
	//  24              3     ,     1     
	biBitCount = 8;
	int lineBytes = (bmpWidth * biBitCount / 8 + 3) / 4 * 4;
	int oldLineBytes = (bmpWidth * 24 / 8 + 3) / 4 * 4;;
	pGrayData = new unsigned char[lineBytes * bmpHeight];
	//memset(pGrayData, 0, bmpInfoHeader.biSizeImage);
	//     ,Windows                  
	//4   (  long   ),    0  ,      biWidth      
	//4    ,     0   4     
	//-------------------------------          --------------------//  
	
	pColorTable = new RGBQUAD[256];
	for (int i = 0; i < 256; i++)
	{
		(*(pColorTable + i)).rgbBlue = i;
		(*(pColorTable + i)).rgbGreen = i;
		(*(pColorTable + i)).rgbRed = i;
		(*(pColorTable + i)).rgbReserved = 0;
	}
	//-------------------------------- RGB      ------------------------//  
	int red, green, blue;
	BYTE gray;
	//char gray_1;

	for (int i = 0; i < bmpHeight; i++)
	{
		//    (pBmpData)          biWidth ,       lineByte   ,  
		//          0,              ,  
		//      biWidth    , lineByte    ,       0    
		for (int j = 0; j < bmpWidth; j++)
		{
			red = *(pBmpBuf + i*oldLineBytes + 3 * j + 2);
			green = *(pBmpBuf + i*oldLineBytes + 3 * j + 1);
			blue = *(pBmpBuf + i*oldLineBytes + 3 * j );
			gray = (BYTE)((77 * red + 151 * green + 28 * blue) >> 8);
			//gray_1 = red*0.299 + green*0.587 + blue*0.114;
			*(pGrayData + i*lineBytes + j) = gray;
		}
	}
	/*
	int threshold=128;
	for (int i = 0; i < bmpHeight; i++)
	{
		//    
		for (int j = 0; j < bmpWidth; j++)
		{
			if (*(pGrayData + i*lineBytes + j)>threshold)
				*(pGrayData + i*lineBytes + j) = 255;
			else
				*(pGrayData + i*lineBytes + j) = 0;
		}
	}
	*/
	char writePath[] = "D:\\C++_file\\image_deal_C++\\IMAGE_JIEQU\\11.bmp";
	saveBmp(writePath, pGrayData, bmpWidth, bmpHeight, biBitCount, pColorTable);
	printf("     ,   bmp  。

"); }