直方图修正和彩色变换

上传人:沈*** 文档编号:163744139 上传时间:2022-10-22 格式:DOC 页数:32 大小:404.50KB
返回 下载 相关 举报
直方图修正和彩色变换_第1页
第1页 / 共32页
直方图修正和彩色变换_第2页
第2页 / 共32页
直方图修正和彩色变换_第3页
第3页 / 共32页
点击查看更多>>
资源描述
第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是由蓝色和黑色组成的,但它实际上是二值图。原来,它的调色板中的两种颜色是黑与蓝,而不是黑与白。所以说二值图也可以是彩色的,只不过一般情况下是黑白图而已。下面的程序实现了反色,注意其中真彩图和调色板位图处理时的差别。BOOL Invert(HWND hWnd) 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; unsigned char Red,Green,Blue; OffBits=bf.bfOffBits-sizeof(BITMAPFILEHEADER); BufSize=OffBits+bi.biHeight*LineBytes; /新开缓冲区的大小 if(hTempImgData=LocalAlloc(LHND,BufSize)=NULL)MessageBox(hWnd,Error alloc memory!,Error Message,MB_OK|MB_ICONEXCLAMATION);return FALSE;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 palPalEntryi.peRed=(BYTE)(255-Red);pPal-palPalEntryi.peGreen=(BYTE)(255-Green); pPal-palPalEntryi.peBlue=(BYTE)(255-Blue); pPal-palPalEntryi.peFlags=0; *(lpTempPtr+)=(unsigned char)(255-Blue); *(lpTempPtr+)=(unsigned char)(255-Green); *(lpTempPtr+)=(unsigned char)(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;ybi.biHeight;y+) lpPtr=(char *)lpImgData+(BufSize-LineBytes-y*LineBytes); lpTempPtr=(char *)lpTempImgData+(BufSize-LineBytes-y*LineBytes); for(x=0;xpalNumEntries =(WORD) NewNumColors; pPal-palVersion = 0x300; if(NumColors=0) /真彩色 for (i = 0; i palPalEntryi.peRed=(BYTE)i; pPal-palPalEntryi.peGreen=(BYTE)i; pPal-palPalEntryi.peBlue=(BYTE)i; pPal-palPalEntryi.peFlags=(BYTE)0; *(lpTempPtr+)=(unsigned char)i; *(lpTempPtr+)=(unsigned char)i; *(lpTempPtr+)=(unsigned char)i; *(lpTempPtr+)=0; else for (i = 0; i palPalEntryi.peRed=Gray; pPal-palPalEntryi.peGreen=Gray; pPal-palPalEntryi.peBlue=Gray; pPal-palPalEntryi.peFlags=0; *(lpTempPtr+)=(unsigned char)Gray; *(lpTempPtr+)=(unsigned char)Gray; *(lpTempPtr+)=(unsigned char)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;ybi.biHeight;y+) lpPtr=(char *)lpImgData+(SrcBufSize-LineBytes-y*LineBytes); lpTempPtr=(char*)lpTempImgData+(DstBufSize-DstLineBytes-y*DstLineBytes); for(x=0;xbi.biWidth;x+) Blue=(unsigned char )(*lpPtr+); Green=(unsigned char )(*lpPtr+); Red=(unsigned char )(*lpPtr+); Y=(float)(Red*0.299+Green*0.587+Blue*0.114); /从位图数据计算得到Y值,写入新图中 Gray=(BYTE)Y; *(lpTempPtr+)=(unsigned char)Gray; if(hBitmap!=NULL) DeleteObject(hBitmap); /产生新的位图hBitmap=CreateDIBitmap(hDc,(LPBITMAPINFOHEADER)lpTempImgData,(LONG)CBM_INIT, (LPSTR)lpTempImgData+sizeof(BITMAPINFOHEADER)+NewNumColors*sizeof(RGBQUAD), (LPBITMAPINFO)lpTempImgData,DIB_RGB_COLORS);if(hPalette & hPrevPalette) SelectPalette(hDc,hPrevPalette,FALSE); RealizePalette(hDc); hf=_lcreat(c:gray.bmp,0); _lwrite(hf,(LPSTR)&DstBf,sizeof(BITMAPFILEHEADER); _lwrite(hf,(LPSTR)lpTempImgData,DstBufSize); _lclose(hf); /释放内存和资源 ReleaseDC(hWnd,hDc); LocalUnlock(hTempImgData); LocalFree(hTempImgData); GlobalUnlock(hImgData); return TRUE;5.3 真彩图转256色图 我们知道,真彩图中包含最多达224种颜色,怎样从中选出256种颜色,又要使颜色的失真比较小,这是一个比较复杂的问题。一种简单的做法是将R:G:B以3:3:2表示,即取R,G的高3位,B的高两位,组成一个字节,这样就可以表示256种颜色了,但不难想象,这种方法的失真肯定很严重。我们下面介绍的算法能够比较好地实现真彩图到256色图的转换。它的思想是:准备一个长度为4096的数组,代表4096种颜色。对图中的每一个象素,取R、G、B的最高四位,拼成一个12位的整数,对应的数组元素加1。全部统计完后,就得到了这4096种颜色的使用频率。其中,可能有一些颜色一次也没用到,即对应的数组元素为零(假设不为零的数组元素共有PalCounts个)。将这些为零的数组元素清除出去,使得前PalCounts个元素都不为零。将这PalCounts个数按从大到小的顺序排列(这里我们使用起泡排序)。这样,前256种颜色就是用的最多的颜色,它们将作为调色板上的256种颜色。对于剩下的PalCounts-256种颜色并不是简单地丢弃,而是用前256种颜色中的一种来代替,代替的原则是找有最小平方误差的那个。再次对图中的每一个象素,取R、G、B的最高四位,拼成一个12位的整数,如果对应值在前256种颜色中,则直接将该索引值填入位图数据中,如果是在后PalCounts-256种颜色中,则用代替色的索引值填入位图数据中。下面的两幅图中,图5.3是原真彩图,图.54是用上面的算法转换成的256色图,可以看出,效果还不错。图5.3 原真彩图图5.4 转换后的256色图下面是上述算法的源程序。BOOL Trueto256(HWND hWnd)DWORD SrcBufSize,OffBits,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; WORD i,j; int Red,Green,Blue,ClrIndex; DWORD ColorHits4096; WORD ColorIndex4096; DWORD PalCounts,temp; long ColorError1,ColorError2; if(NumColors!=0) /NumColors不为零,所以不是真彩图MessageBox(hWnd,Must be a true color bitmap!,Error Message,MB_OK|MB_ICONEXCLAMATION);return FALSE;/由于颜色位数有可能发生了改变,所以要重新计算每行占用的字节数以及/新图的缓冲区大小 DstLineBytes=(DWORD)WIDTHBYTES(bi.biWidth*8); DstBufSize=(DWORD)(sizeof(BITMAPINFOHEADER)+256*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)(256*sizeof(RGBQUAD)+sizeof(BITMAPFILEHEADER) +sizeof(BITMAPINFOHEADER); DstBi.biClrUsed=0; DstBi.biBitCount=8; /OffBits为到实际位图数据的偏移值 OffBits=bf.bfOffBits-sizeof(BITMAPFILEHEADER); /SrcBufSize为原图缓冲区的大小SrcBufSize=OffBits+bi.biHeight*LineBytes; if(hTempImgData=LocalAlloc(LHND,DstBufSize)=NULL)MessageBox(hWnd,Error alloc memory!,Error Message,MB_OK|MB_ICONEXCLAMATION); return FALSE; lpImgData=(LPBITMAPINFOHEADER)GlobalLock(hImgData); lpTempImgData=(LPBITMAPINFOHEADER)LocalLock(hTempImgData); /拷贝位图数据 memcpy(lpTempImgData,lpImgData,OffBits);/用新的头信息取代旧的头信息 memcpy(lpTempImgData,(char *)&DstBi,sizeof(BITMAPINFOHEADER);/ColorHits为记录颜色使用频率的数组,ColorIndex为记录颜色索引值的/数组/先全部清零 memset(ColorHits,0,4096*sizeof(DWORD); memset(ColorIndex,0,4096*sizeof(WORD); for(y=0;ybi.biHeight;y+) lpPtr=(unsigned char *)lpImgData+(SrcBufSize-LineBytes-y*LineBytes); for(x=0;xbi.biWidth;x+) /R,G,B各取4位 Blue=(int)(*(lpPtr+) & 0xf0); Green=(int)(*(lpPtr+) & 0xf0); Red=(int)(*(lpPtr+) & 0xf0); /拼成一个12位整数 ClrIndex=(Blue4); /相应的数组元素加1 ColorHitsClrIndex+; PalCounts=0;/将为零的元素清除出去 for (ClrIndex = 0; ClrIndex 4096; ClrIndex+) if(ColorHitsClrIndex!=0) ColorHitsPalCounts=ColorHitsClrIndex; /注意调整相应的索引值 ColorIndexPalCounts=ClrIndex; PalCounts+; /颜色数加1 /用起泡排序将PalCounts种颜色按从大到小的顺序排列 for (i = 0; i PalCounts-1; i+) for (j = i + 1; j ColorHitsi) temp = ColorHitsi; ColorHitsi = ColorHitsj; ColorHitsj = temp; /注意调整相应的索引值 temp = ColorIndexi; ColorIndexi = ColorIndexj; ColorIndexj = (WORD)temp; /为新的调色板分配内存 hPal=LocalAlloc(LHND,sizeof(LOGPALETTE) +256* sizeof(PALETTEENTRY); pPal =(LOGPALETTE *)LocalLock(hPal); pPal-palNumEntries =(WORD) 256; pPal-palVersion = 0x300; lpTempPtr=(char *)lpTempImgData+sizeof(BITMAPINFOHEADER); for (i = 0; i palPalEntryi.peRed=(BYTE)(ColorIndexi & 0x00f) palPalEntryi.peGreen=(BYTE)(ColorIndexi & 0x0f0); pPal-palPalEntryi.peBlue=(BYTE)(ColorIndexi & 0xf00) 4); pPal-palPalEntryi.peFlags=(BYTE)0; *(lpTempPtr+)=(unsigned char)(ColorIndexi & 0xf00) 4); *(lpTempPtr+)=(unsigned char)(ColorIndexi & 0x0f0); *(lpTempPtr+)=(unsigned char)(ColorIndexi & 0x00f) 256) for (i = 256; i 4); Green = (long)(ColorIndexi & 0x0f0); Red = (long)(ColorIndexi & 0x00f) 4); ClrIndex = 0; for (j = 0; j palPalEntryj.peBlue)*(Blue-pPal-palPalEntryj.peBlue)+ (long)(Green-pPal-palPalEntryj.peGreen)*(Green-pPal-palPalEntryj.peGreen)+ (long)(Red-pPal-palPalEntryj.peRed)*(Red-pPal-palPalEntryj.peRed); if (ColorError2 ColorError1) /找到更小的了 ColorError1 = ColorError2; ClrIndex = j; /记录对应的调色板的索引值 /ColorHits记录12位索引值对应的调色板中的索引值 ColorHitsi = ClrIndex; if(hPalette!=NULL) DeleteObject(hPalette);/产生新的逻辑调色板 hPalette=CreatePalette(pPal); LocalUnlock(hPal); LocalFree(hPal); hDc=GetDC(hWnd); if(hPalette) hPrevPalette=SelectPalette(hDc,hPalette,FALSE); RealizePalette(hDc); for(y=0;ybi.biHeight;y+) lpPtr=(char *)lpImgData+(SrcBufSize-LineBytes-y*LineBytes); lpTempPtr=(char*)lpTempImgData+(DstBufSize-DstLineBytes-y*DstLineBytes); for(x=0;xbi.biWidth;x+) /R,G,B各取4位 Blue=(int)(*(lpPtr+) & 0xf0); Green=(int)(*(lpPtr+) & 0xf0); Red=(int)(*(lpPtr+) & 0xf0); /拼成一个12位整数 ClrIndex=(Blue4); for (i = 0; i PalCounts;i+) if (ClrIndex = ColorIndexi)/根据12索引值取得对应的调色板中的索引值*(lpTempPtr+)=(unsigned char)ColorHitsi; break; if(hBitmap!=NULL) DeleteObject(hBitmap); /产生新的位图 hBitmap=CreateDIBitmap(hDc,(LPBITMAPINFOHEADER)lpTempImgData,(LONG)CBM_INIT,(LPSTR)lpTempImgData+sizeof(BITMAPINFOHEADER)+256*sizeof(RGBQUAD), (LPBITMAPINFO)lpTempImgData,DIB_RGB_COLORS);if(hPalette & hPrevPalette) SelectPalette(hDc,hPrevPalette,FALSE); RealizePalette(hDc); hf=_lcreat(c:256.bmp,0); _lwrite(hf,(LPSTR)&DstBf,sizeof(BITMAPFILEHEADER); _lwrite(hf,(LPSTR)lpTempImgData,DstBufSize); _lclose(hf); /释放内存和资源 ReleaseDC(hWnd,hDc);
展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 管理文书 > 施工组织


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!