如何将真彩色转换为256色彩色图片?

yoyoto 2003-05-06 04:54:38
不好意思,上午问过这个问题,wangmuzi小哥给我提供的是转换为256色灰度图像的代码,小生需要的是256色彩色图片,或许二者有相通之处,可是小生天生愚笨,不知道该如何修改,还望高人指点:(附代码)
BOOL WINAPI TruecolorTo256(LPSTR lpDIB, LONG lWidth, LONG lHeight)
{
LONG i;
LONG j;

LPSTR lpDIBBits;
LPSTR lpTemplateDIBBits;


BYTE * lpSrc;
BYTE * lpDst;

//ͼÏñÿÐеÄ×Ö½ÚÊý
LONG lSrcLineBytes;
LONG lDstLineBytes;

//Ö¸ÏòDIBµÄÖ¸Õë
LPSTR lpTemplateDIB;
HLOCAL hTemplateDIB;

//Ö¸ÏòBITMAPINFOHEADERµÄÖ¸Õë
LPBITMAPINFOHEADER lpBIH;

//Ö¸ÏòBITMAPINFOµÄÖ¸Õë
LPBITMAPINFO lpBI;

//¼ÆËãת»»Ç°DIB³¤¶È
DWORD dwSrcDIBSize = sizeof(BITMAPINFOHEADER) + lWidth * lHeight * 3;
//¼ÆËãת»»ºóDIB³¤¶È
DWORD dwDesDIBSize = sizeof(BITMAPINFOHEADER) + 4 * 256
+ lWidth * lHeight;

//ΪDIB·ÖÅäÄÚ´æ
hTemplateDIB = GlobalAlloc(GHND, dwDesDIBSize * 8);

if( hTemplateDIB == NULL)
{
//ÄÚ´æ·ÖÅäʧ°Ü£¬·µ»ØFALSE
return FALSE;
}

//Ëø¶¨ÄÚ´æ
lpTemplateDIB = (LPSTR) ::GlobalLock((HGLOBAL) hTemplateDIB);

//¼ÆËãͼÏñÿÐеÄ×Ö½ÚÊý
lSrcLineBytes = WIDTHBYTES(lWidth * 8 * 3);
lDstLineBytes = WIDTHBYTES(lWidth * 8);

//¸³³õÖµ
memcpy(lpTemplateDIB, lpDIB, sizeof(BITMAPINFOHEADER));
lpBIH = (LPBITMAPINFOHEADER) lpTemplateDIB;
lpBI = (LPBITMAPINFO) lpTemplateDIB;
lpBIH->biBitCount = 8;

//ÕÒµ½DIBͼÏñµÄÏñËØÆðʼλÖÃ
lpDIBBits = ::FindDIBBits(lpDIB);
lpTemplateDIBBits = ::FindDIBBits(lpTemplateDIB);

for(i = 0; i < 256; i++)
{
lpBI->bmiColors[i].rgbRed = (BYTE)i;
lpBI->bmiColors[i].rgbGreen = (BYTE)i;
lpBI->bmiColors[i].rgbBlue = (BYTE)i;
lpBI->bmiColors[i].rgbReserved = 0x00;
}

for(i = 0; i < lHeight; i++)
{
for(j = 0; j < lWidth; j++)
{
//Ö¸ÏòԭͼÏñºÍÄ¿µÄͼÏñµÄµÚiÐУ¬µÚj¸öÏñËصÄÖ¸Õë
lpSrc = (unsigned char *)lpDIBBits + lSrcLineBytes * i + j * 3;
lpDst = (unsigned char *)lpTemplateDIBBits + lDstLineBytes * i + j;

//¸øת»»ºóµÄͼÏñÏñËظ³Öµ
*lpDst = (BYTE)(0.299 * (*lpSrc) + 0.587 * (*(lpSrc+1))
+ 0.114 * (*(lpSrc+2)));
}
}
memset(lpDIB, 0, dwSrcDIBSize);
memcpy(lpDIB, lpTemplateDIB, dwDesDIBSize);

//ÊÍ·ÅÄÚ´æ
GlobalUnlock(hTemplateDIB);
GlobalFree(hTemplateDIB);

return TRUE;
}
...全文
327 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
s6283 2003-05-12
  • 打赏
  • 举报
回复
用octree算法进行色彩量化
http://www.codeproject.com/bitmap/cquantizer.asp
lazio88 2003-05-12
  • 打赏
  • 举报
回复
//打开文件
CFileDialog dlg(TRUE,_T("BMP"),_T("*.BMP"),OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,_T("位图文件(*.BMP)|*.TXT|"));
CFile file;
CFileException fe;
if(dlg.DoModal()==IDOK)
{
CString filepathname=dlg.GetPathName();//打开的文件路径赋给filepathname
//就是你指的CString类型转化处吧?
// m_Dib.Load(filepathname);//这句是为显示做准备的
if(!file.Open(filepathname,CFile::modeRead|CFile::shareDenyWrite,&fe))
{
//失败
//ReportSaveLoadException()
return;
}
TRY
{
hDIB=::ReadDIBFile(file);//这里,为转化准备
}
CATCH(CFileException,eLoad) //ReadDIBFile()是那个
{ //DIBAPI.H类中的一个函数
//读取失败
file.Abort();
//报告失败
//ReportSaveLoadException(
//设置DIB为空
hDIB=NULL;
return;
}
END_CATCH
pDIB=(LPSTR)::GlobalLock((HGLOBAL)hDIB);//指向DIB的指针,不就转化了吗
jijuzheng 2003-05-11
  • 打赏
  • 举报
回复
http://www.vckbase.com/code/listcode.asp?mclsid=7&sclsid=703
herrycsdn 2003-05-10
  • 打赏
  • 举报
回复
这涉及到颜色量化的问题,有不少现成的算法
lazio88 2003-05-10
  • 打赏
  • 举报
回复
我刚刚改过的,简单一点
void ChangeTo256(LPSTR pDIB)
{
// TODO: Add your control notification handler code here
if(pDIB==NULL)
{
MessageBox("error");
return;
}
BeginWaitCursor();
BYTE ired,igreen,iblue;
long p,q;
LPBITMAPINFOHEADER pnewbmpinfo;//新图像信息头
long lineGrayBytes=WIDTHBYTES(Width*8);//256色每行字节数
// long lineGrayBytes=(Width+3)&~3;//也可以
BYTE* lpdest;//新位图指针
lpdest=(BYTE*)::malloc(Height*lineGrayBytes);
memset(lpdest,0,lineGrayBytes*Height);//初始化为0
int n=0;
for(p=0;p<Height;p++)
for(q=0;q<Width;n++,q++)
{
ired=*(lpNewDIBBits+p*lineNewBytes+q*3+2);
igreen=*(lpNewDIBBits+p*lineNewBytes+q*3+1);
iblue=*(lpNewDIBBits+p*lineNewBytes+q*3);
lpdest[p*lineGrayBytes+q]=(BYTE)((float)(0.299*ired)+(float)(0.587*igreen)+(float)(0.114*iblue));
}
pnewbmpinfo->biBitCount=8;
//设置调色板
RGBQUAD* lpRGBquad;
lpRGBquad=(RGBQUAD*)&pDIB[sizeof(BITMAPINFOHEADER)];//在信息头后
for(p=0;p<=256;p++)
{
lpRGBquad[p].rgbRed=(unsigned char)p;
lpRGBquad[p].rgbGreen=(unsigned char)p;
lpRGBquad[p].rgbBlue=(unsigned char)p;

lpRGBquad[p].rgbReserved=0;
}
lpGrayDIBBits=::FindDIBBits(pDIB);
BYTE* lpSrc;//原图像
for(p=0;p<Height*lineGrayBytes;p++)
{
lpSrc=(BYTE*)lpGrayDIBBits+p;
*lpSrc=lpdest[p];
}
::free((void*)lpdest);
CClientDC dc(this);
CDC* pDC=(CDC*)(&dc);
::StretchDIBits(pDC->m_hDC,/*START_POINT_X*/0,/*START_POINT_Y*/0,Width,Height,0,0,Width,Height,lpGrayDIBBits,(LPBITMAPINFO)pDIB,DIB_RGB_COLORS,SRCCOPY);
EndWaitCursor();

}

yoyoto 2003-05-10
  • 打赏
  • 举报
回复
lazio88(cameo)大虾,我试着将你的程序以入我的程序,可是缺少FindDIBBits函数,并且最后一步:::StretchDIBits(pDC->m_hDC,/*START_POINT_X*/0,/*START_POINT_Y*/0,Width,Height,0,0,Width,Height,lpGrayDIBBits,(LPBITMAPINFO)pDIB,DIB_RGB_COLORS,SRCCOPY);
出现这样的错误:E:\图像处理\class11\bmp1View.cpp(734) : error C2440: 'type cast' : cannot convert from 'class CDib' to 'struct tagBITMAPINFO *'
请问这个错误如何修改?
duwenyong 2003-05-08
  • 打赏
  • 举报
回复
////////////////////////////////////////////////////////////////
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 ColorHits[4096];
WORD ColorIndex[4096];
DWORD PalCounts,temp;
long ColorError1,ColorError2;

if(NumColors!=0){
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);
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=bf.bfOffBits-sizeof(BITMAPFILEHEADER);
SrcBufSize=bf.bfSize-sizeof(BITMAPFILEHEADER);

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);

//copy image data
memcpy(lpTempImgData,lpImgData,OffBits);
//overwrite bitmapinfoheader with the new one
memcpy(lpTempImgData,(char *)&DstBi,sizeof(BITMAPINFOHEADER));

memset(ColorHits,0,4096*sizeof(DWORD));
memset(ColorIndex,0,4096*sizeof(WORD));
for(y=0;y<bi.biHeight;y++){
lpPtr=(unsigned char *)lpImgData+(SrcBufSize-LineBytes-y*LineBytes);
for(x=0;x<bi.biWidth;x++){
Blue=(int)(*(lpPtr++) & 0xf0);
Green=(int)(*(lpPtr++) & 0xf0);
Red=(int)(*(lpPtr++) & 0xf0);
ClrIndex=(Blue<<4) + Green +(Red >>4);
ColorHits[ClrIndex]++;
}
}

PalCounts=0;
//pack the color table
for (ClrIndex = 0; ClrIndex < 4096; ClrIndex++)
{
if(ColorHits[ClrIndex]!=0){
ColorHits[PalCounts]=ColorHits[ClrIndex];
ColorIndex[PalCounts]=ClrIndex;
PalCounts++;
}
}
//sort the color table downsize
for (i = 0; i < PalCounts-1; i++)
for (j = i + 1; j < PalCounts; j++){
if (ColorHits[j] > ColorHits[i]){
temp = ColorHits[i];
ColorHits[i] = ColorHits[j];
ColorHits[j] = temp;
temp = ColorIndex[i];
ColorIndex[i] = ColorIndex[j];
ColorIndex[j] = (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 < 256; i++) {
pPal->palPalEntry[i].peRed=(BYTE)((ColorIndex[i] & 0x00f) << 4);
pPal->palPalEntry[i].peGreen=(BYTE)((ColorIndex[i] & 0x0f0));
pPal->palPalEntry[i].peBlue=(BYTE)((ColorIndex[i] & 0xf00) >> 4);
pPal->palPalEntry[i].peFlags=(BYTE)0;
*(lpTempPtr++)=(unsigned char)((ColorIndex[i] & 0xf00) >> 4);
*(lpTempPtr++)=(unsigned char)((ColorIndex[i] & 0x0f0));
*(lpTempPtr++)=(unsigned char)((ColorIndex[i] & 0x00f) << 4);
*(lpTempPtr++)=0;
ColorHits[i]=i;
}

//其余的颜色依据最小平方差近似为前256中最接近的一种
if (PalCounts > 256){
for (i = 256; i < PalCounts; i++){
ColorError1=1000000000;
Blue = (long)((ColorIndex[i] & 0xf00) >> 4);
Green = (long)((ColorIndex[i] & 0x0f0));
Red = (long)((ColorIndex[i] & 0x00f) << 4);
ClrIndex = 0;
for (j = 0; j < 256; j++){
ColorError2=(long)(Blue-pPal->palPalEntry[j].peBlue)*(Blue-pPal->palPalEntry[j].peBlue)+
(long)(Green-pPal->palPalEntry[j].peGreen)*(Green-pPal->palPalEntry[j].peGreen)+
(long)(Red-pPal->palPalEntry[j].peRed)*(Red-pPal->palPalEntry[j].peRed);
if (ColorError2 < ColorError1){
ColorError1 = ColorError2;
ClrIndex = j;
}
}
ColorHits[i] = ClrIndex;
}
}

if(hPalette!=NULL)
DeleteObject(hPalette);

//create new logic palette
hPalette=CreatePalette(pPal);
LocalUnlock(hPal);
LocalFree(hPal);

hDc=GetDC(hWnd);
if(hPalette){
hPrevPalette=SelectPalette(hDc,hPalette,FALSE);
RealizePalette(hDc);
}

for(y=0;y<bi.biHeight;y++){
lpPtr=(char *)lpImgData+(SrcBufSize-LineBytes-y*LineBytes);
lpTempPtr=(char *)lpTempImgData+(DstBufSize-DstLineBytes-y*DstLineBytes);
for(x=0;x<bi.biWidth;x++){
Blue=(int)(*(lpPtr++) & 0xf0);
Green=(int)(*(lpPtr++) & 0xf0);
Red=(int)(*(lpPtr++) & 0xf0);
ClrIndex=(Blue<<4) + Green +(Red >>4);
for (i = 0; i < PalCounts;i++)
if (ClrIndex == ColorIndex[i]){
*(lpTempPtr++)=(unsigned char)ColorHits[i];
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);
LocalUnlock(hTempImgData);
LocalFree(hTempImgData);
GlobalUnlock(hImgData);
return TRUE;
}
stoneintheair 2003-05-07
  • 打赏
  • 举报
回复
哈,我也有同样的问题。我这有一点思路。
它的思想是:准备一个长度为4096的数组,代表4096种颜色。
对图中的每一个像素,取R,G,B的最高四位,拼成一个12位的整数,
对应的数组元素加1。全部统计完后,就得到了这4096种颜色的使用频率。
这其中,可能有一些颜色一次也没用到,即对应的数组元素为零
(假设不为零的数组元素共有M个)。将这些为零的数组元素清除出去,
使得前M个元素都不为零。将这M个数按从大到小的顺序排列,这样,
前256种颜色就是用的最多的颜色,它们将作为调色板上的256种颜色。
对于剩下的M-256种颜色并不是简单的丢弃,而是用前256种颜色中的
一种来代替,代替的原则是找有最小平方误差的那个。
存在的问题: 在该算法中 只取了R、G、B的最高四位,
这样剩下的几位被舍去,会使图像亮度降低。
当也可以取全R、G、B的八位,那样效率太低。
我们可以加上一个小于16的随机数来补偿。
如果你找到更好的别忘了告诉我。

yoyoto 2003-05-06
  • 打赏
  • 举报
回复
可是,我不想使用动态连接库,我需要将这段代码嵌进程序中使用!不过,还是谢谢你,大伙还有什么高见吗?
Skt32 2003-05-06
  • 打赏
  • 举报
回复
http://www.vckbase.com/code/listcode.asp?mclsid=7&sclsid=&page=3

真彩位图转化成256彩色或黑白位图的代码 详细信息 < 图像格式 >

一个效果非常好的24,16bit真彩位图转化成256彩色或黑白位图的演示程序代码,其中调用了一个动态连接库。

19,468

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 图形处理/算法
社区管理员
  • 图形处理/算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧