Blue=(unsignedchar)(*lpPtr++);
Green=(unsignedchar)(*lpPtr++);
Red=(unsignedchar)(*lpPtr++);
//反转位图数据中的颜色,存入新的位图数据中
*(lpTempPtr++)=(unsignedchar)(255-Blue);
*(lpTempPtr++)=(unsignedchar)(255-Green);
*(lpTempPtr++)=(unsignedchar)(255-Red);
}
}
}
if(hBitmap!
=NULL)
DeleteObject(hBitmap);
hBitmap=CreateDIBitmap(hDc,(LPBITMAPINFOHEADER)lpTempImgData,
(LONG)CBM_INIT,
(LPSTR)lpTempImgData+
sizeof(BITMAPINFOHEADER)+
NumColors*sizeof(RGBQUAD),
(LPBITMAPINFO)lpTempImgData,
DIB_RGB_COLORS);
if(hPalette&&hPrevPalette){
SelectPalette(hDc,hPrevPalette,FALSE);
RealizePalette(hDc);
}
hf=_lcreat("c:
\\invert.bmp",0);
_lwrite(hf,(LPSTR)&bf,sizeof(BITMAPFILEHEADER));
_lwrite(hf,(LPSTR)lpTempImgData,BufSize);
_lclose(hf);
//释放内存和资源
ReleaseDC(hWnd,hDc);
LocalUnlock(hTempImgData);
LocalFree(hTempImgData);
GlobalUnlock(hImgData);
returnTRUE;
}
5.2彩色图转灰度图
第2章中提到了YUV的颜色表示方法,在这种表示方法中,Y分量的物理含义就是亮度,它含了灰度图(grayscale)的所有信息,只用Y分量就完全能够表示出一幅灰度图来。
YUV和RGB之间有着如下的对应关系:
我们利用上式,根据R、G、B的值求出Y值后,将R、G、B值都赋值成Y,就能表示出灰度图来,这就是彩色图转灰度图的原理。
先看看真彩图。
我们知道真彩图不带调色板,每个象素用3个字节,表示R、G、B三个分量。
所以处理很简单,根据R、G、B的值求出Y值后,将R、G、B值都赋值成Y,写入新图即可。
再来看看带调色板的彩色图,我们知道位图中的数据只是对应调色板中的一个索引值,我们只需要将调色板中的彩色变成灰度,形成新调色板,而位图数据不用动,就可以了。
下面的程序实现了彩色图到灰度图的转换,注意其中真彩图和调色板位图处理时的差别。
BOOLColortoGrayScale(HWNDhWnd)
{
DWORD SrcOffBits,SrcBufSize,DstBufSize,DstLineBytes;
LPBITMAPINFOHEADER lpImgData;
LPSTR lpPtr;
HLOCAL hTempImgData;
LPBITMAPINFOHEADER lpTempImgData;
LPSTR lpTempPtr;
HDC hDc;
HFILE hf;
LONG x,y;
BITMAPFILEHEADER DstBf;
BITMAPINFOHEADER DstBi;
LOGPALETTE *pPal;
HPALETTE hPrevPalette;
HLOCAL hPal;
DWORD NewNumColors;
WORD NewBitCount;
float Y;
DWORD i;
unsignedchar Red,Green,Blue,Gray;
NewNumColors=NumColors;//NewNumColors为新图的颜色数
NewBitCount=bi.biBitCount; //NewBitCount为新图的颜色位数
if(NumColors==0)//真彩图
{
NewNumColors=256;
NewBitCount=8;
}
//由于颜色位数有可能发生了改变,所以要重新计算每行占用的字节数以及
//新图的缓冲区大小
DstLineBytes=(DWORD)WIDTHBYTES(bi.biWidth*NewBitCount);
DstBufSize=(DWORD)(sizeof(BITMAPINFOHEADER)+NewNumColors*
sizeof(RGBQUAD)+(DWORD)DstLineBytes*bi.biHeight);
//DstBf和DstBi为新的BITMAPFILEHEADER和BITMAPINFOHEADER
//拷贝原来的头信息
memcpy((char*)&DstBf,(char*)&bf,sizeof(BITMAPFILEHEADER));
memcpy((char*)&DstBi,(char*)&bi,sizeof(BITMAPINFOHEADER));
//做必要的改变
DstBf.bfSize=DstBufSize+sizeof(BITMAPFILEHEADER);
DstBf.bfOffBits=(DWORD)(NewNumColors*sizeof(RGBQUAD)+
sizeof(BITMAPFILEHEADER)+
sizeof(BITMAPINFOHEADER));
DstBi.biClrUsed=0;
DstBi.biBitCount=NewBitCount;
//原图的缓冲区的大小
SrcOffBits=bf.bfOffBits-sizeof(BITMAPFILEHEADER);
SrcBufSize=SrcOffBits+bi.biHeight*LineBytes;
if((hTempImgData=LocalAlloc(LHND,DstBufSize))==NULL)
{
MessageBox(hWnd,"Errorallocmemory!
","ErrorMessage",MB_OK|
MB_ICONEXCLAMATION);
returnFALSE;
}
lpImgData=(LPBITMAPINFOHEADER)GlobalLock(hImgData);
lpTempImgData=(LPBITMAPINFOHEADER)LocalLock(hTempImgData);
//拷贝头信息和位图数据
memcpy(lpTempImgData,lpImgData,DstBufSize);
//用新的BITMAPINFOHEADER替换原来的头信息
memcpy(lpTempImgData,(char*)&DstBi,sizeof(BITMAPINFOHEADER));
//lpPtr指向原图的数据
lpPtr=(char*)lpImgData+sizeof(BITMAPINFOHEADER);
//lpTempPtr指向新图的数据
lpTempPtr=(char*)lpTempImgData+sizeof(BITMAPINFOHEADER);
//为新的调色板分配内存
hPal=LocalAlloc(LHND,sizeof(LOGPALETTE)+NewNumColors
*sizeof(PALETTEENTRY));
pPal=(LOGPALETTE*)LocalLock(hPal);
pPal->palNumEntries=(WORD)NewNumColors;
pPal->palVersion =0x300;
if(NumColors==0)//真彩色
for(i=0;i<256;i++){//灰度从(0,0,0)到(255,255,255)
pPal->palPalEntry[i].peRed=(BYTE)i;
pPal->palPalEntry[i].peGreen=(BYTE)i;
pPal->palPalEntry[i].peBlue=(BYTE)i;
pPal->palPalEntry[i].peFlags=(BYTE)0;
*(lpTempPtr++)=(unsignedchar)i;
*(lpTempPtr++)=(unsignedchar)i;
*(lpTempPtr++)=(unsignedchar)i;
*(lpTempPtr++)=0;
}
else
for(i=0;i Blue=(unsignedchar)(*lpPtr++);
Green=(unsignedchar)(*lpPtr++);
Red=(unsignedchar)(*lpPtr++);
Y=(float)(Red*0.299+Green*0.587+Blue*0.114);
Gray=(BYTE)Y;
lpPtr++;
//从原来的调色板中的颜色计算得到Y值,写入新的调色板
pPal->palPalEntry[i].peRed=Gray;
pPal->palPalEntry[i].peGreen=Gray;
pPal->palPalEntry[i].peBlue=Gray;
pPal->palPalEntry[i].peFlags=0;
*(lpTempPtr++)=(unsignedchar)Gray;
*(lpTempPtr++)=(unsignedchar)Gray;
*(lpTempPtr++)=(unsignedchar)Gray;
*(lpTempPtr++)=0;
}
if(hPalette!
=NULL)
DeleteObject(hPalette);
//生成新的逻辑调色板
hPalette=CreatePalette(pPal);
LocalUnlock(hPal);
LocalFree(hPal);
hDc=GetDC(hWnd);
if(hPalette){
hPrevPalette=SelectPalette(hDc,hPalette,FALSE);
RealizePalette(hDc);
}
if(NumColors==0)//真彩色图才需要处理位图数据
for(y=0;y lpPtr=(char*)lpImgData+(SrcBufSize-LineBytes-y*LineBytes);
lpTempPtr=(char*)lpTempImgData+
(DstBufSize-DstLineBytes-y*DstLineBytes);
for(x=0;x Blue=(unsignedchar)(*lpPtr++);