直方图修正和彩色变换.docx
- 文档编号:12666038
- 上传时间:2023-04-21
- 格式:DOCX
- 页数:47
- 大小:268.65KB
直方图修正和彩色变换.docx
《直方图修正和彩色变换.docx》由会员分享,可在线阅读,更多相关《直方图修正和彩色变换.docx(47页珍藏版)》请在冰豆网上搜索。
直方图修正和彩色变换
第5章直方图修正和彩色变换
这一章,我们主要和调色板打交道。
先从最简单的反色讲起。
5.1反色
反色(invert)就是形成底片效果。
例如,图5.2为图5.1反色后的结果。
图5.1 原图
图5.2 图5.1反色后的结果
反色有时是很有用的,比如,图5.1中黑色区域占绝大多数,这样打印起来很费墨,我们可以先进行反色处理后再打印。
反色的实际含义是将R、G、B值反转。
若颜色的量化级别是256,则新图的R、G、B值为255减去原图的R、G、B值。
这里针对的是所有图,包括真彩图、带调色板的彩色图(又称为伪彩色图)、和灰度图。
针对不同种类有不同的处理。
先看看真彩图。
我们知道真彩图不带调色板,每个象素用3个字节,表示R、G、B三个分量。
所以处理很简单,把反转后的R、G、B值写入新图即可。
再来看看带调色板的彩色图,我们知道位图中的数据只是对应调色板中的一个索引值,我们只需要将调色板中的颜色反转,形成新调色板,而位图数据不用动,就能够实现反转。
灰度图是一种特殊的伪彩色图,只不过调色板中的R、G、B值都是一样的而已。
所以反转的处理和上面讲的一样。
这里,我想澄清一个概念。
过去我们讲二值图时,一直都说成黑白图。
二值位图一定是黑白的吗?
答案是不一定。
我们安装Windows95时看到的那幅setup.bmp是由蓝色和黑色组成的,但它实际上是二值图。
原来,它的调色板中的两种颜色是黑与蓝,而不是黑与白。
所以说二值图也可以是彩色的,只不过一般情况下是黑白图而已。
下面的程序实现了反色,注意其中真彩图和调色板位图处理时的差别。
BOOLInvert(HWNDhWnd)
{
DWORD OffBits,BufSize;
LPBITMAPINFOHEADER lpImgData;
LPSTR lpPtr;
HLOCAL hTempImgData;
LPBITMAPINFOHEADER lpTempImgData;
LPSTR lpTempPtr;
HDC hDc;
HFILE hf;
LONG x,y;
LOGPALETTE *pPal;
HPALETTE hPrevPalette=NULL;
HLOCAL hPal;
DWORD i;
unsignedchar Red,Green,Blue;
OffBits=bf.bfOffBits-sizeof(BITMAPFILEHEADER);
BufSize=OffBits+bi.biHeight*LineBytes;//新开缓冲区的大小
if((hTempImgData=LocalAlloc(LHND,BufSize))==NULL)
{
MessageBox(hWnd,"Errorallocmemory!
","ErrorMessage",MB_OK|
MB_ICONEXCLAMATION);
returnFALSE;
}
lpImgData=(LPBITMAPINFOHEADER)GlobalLock(hImgData);
lpTempImgData=(LPBITMAPINFOHEADER)LocalLock(hTempImgData);
//拷贝头信息
memcpy(lpTempImgData,lpImgData,BufSize);
hDc=GetDC(hWnd);
if(NumColors!
=0){//NumColors不为0说明是带调色板的
lpPtr=(char*)lpImgData+sizeof(BITMAPINFOHEADER);
//指向原图数据
lpTempPtr=(char*)lpTempImgData+sizeof(BITMAPINFOHEADER);
//指向新图数据
//为新调色板分配内存
hPal=LocalAlloc(LHND,sizeof(LOGPALETTE)+
NumColors*sizeof(PALETTEENTRY));
pPal=(LOGPALETTE*)LocalLock(hPal);
pPal->palNumEntries=(WORD)NumColors;
pPal->palVersion =0x300;
for(i=0;i Blue=(unsignedchar)(*lpPtr++); Green=(unsignedchar)(*lpPtr++); Red=(unsignedchar)(*lpPtr++); lpPtr++; //反转调色板中的颜色,存入新的调色板 pPal->palPalEntry[i].peRed=(BYTE)(255-Red); pPal->palPalEntry[i].peGreen=(BYTE)(255-Green); pPal->palPalEntry[i].peBlue=(BYTE)(255-Blue); pPal->palPalEntry[i].peFlags=0; *(lpTempPtr++)=(unsignedchar)(255-Blue); *(lpTempPtr++)=(unsignedchar)(255-Green); *(lpTempPtr++)=(unsignedchar)(255-Red); *(lpTempPtr++)=0; } if(hPalette! =NULL) DeleteObject(hPalette); hPalette=CreatePalette(pPal);//产生新的调色板 LocalUnlock(hPal); LocalFree(hPal); if(hPalette){ hPrevPalette=SelectPalette(hDc,hPalette,FALSE); RealizePalette(hDc); } } else{//不带调色板,说明是真彩色图 for(y=0;y lpPtr=(char*)lpImgData+(BufSize-LineBytes-y*LineBytes); lpTempPtr=(char*)lpTempImgData+(BufSize-LineBytes-y*LineBytes); for(x=0;x 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++);
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 直方图 修正 彩色 变换
![提示](https://static.bdocx.com/images/bang_tan.gif)