24位转8位位图,不是灰度,有颜色的,尽量减少失真
来源:互联网 发布:淘宝金冠店铺可信吗 编辑:程序博客网 时间:2024/09/21 09:06
具体做法见函数内注释
void CDib::ConverTo8Bit()
{
//24位转8位,尽量减少失真
//方法:
//首先根据24位图颜色信息,取颜色的高4位进行组合成12位的信息,然后作为索引记录数组,数组内容记录出现的次数
//然后对数组排序,计算颜色命中次数,取最大的256种作为调色板
//对24位位图中其他颜色计算平方误差,用调色板中颜色与24位各点颜色差的平方,再把红绿蓝三色作和,取结果,最小的最为匹配
//将最匹配的256色调色板索引写入256色位图相应的位置,并保存
LPBITMAPINFOHEADER lpbi;
if(!hdib)
return;
lpbi = (BITMAPINFOHEADER*)hdib;
int height = lpbi->biHeight;
//两个宽度
LONG lLineBytes24=((lpbi->biWidth*24+31)/32*4);
LONG lLineBytes8=((lpbi->biWidth*8+31)/32*4);
//源图像的指针
BYTE* srcBits =NULL;
//使其指向源图像的图像数据起始地址
srcBits = (BYTE*)lpbi+sizeof(BITMAPINFOHEADER);
//转换后的图像数据指针(大小为图片大小和调色板大小之和
int iPaletteSize = sizeof(RGBQUAD)*256;//调色板大小
BYTE* dstBits = (BYTE*)malloc(iPaletteSize+lLineBytes8*height);
RGBQUAD* pRGB = (RGBQUAD *)dstBits;//调色板指针,指向数据部分开始地址
//寻找原来24位图里的颜色信息,并按出现的频率加权值
DWORD ColorHits[4096]; //颜色命中
WORD ColorIndex[4096]; //颜色索引
//ColorHits为记录颜色使用频率的数组,ColorIndex为记录颜色索引值的数组
memset(ColorHits, 0, 4096 * sizeof(DWORD));
memset(ColorIndex, 0, 4096 * sizeof(WORD));
//计算命中次数
for(int y=0; y<height; y++)
{
BYTE* lpBits=srcBits+y*lLineBytes24;
for(int x=0; x<lLineBytes24; )
{
int B = (int)(*(lpBits+x)&0xf0); //只取高四位
x++;
int G = (int)(*(lpBits+x)&0xf0);
x++;
int R = (int)(*(lpBits+x)&0xf0);
x++;
int ClrIndex=(B<<4) + G + (R>>4); //拼成一个位整数,由于只取高四位,故拼后为4*3=12位,即2的12次方为4096项,所以索引里为4096大小的数组
ColorHits[ClrIndex]++;//命中次数加1
}
}
DWORD PalCounts=0;//最多调色板项数目
//清除数组中为0的元素,为下面的排序提高效率
for(int ClrIndex=0; ClrIndex<4096; ClrIndex++)
{
if( ColorHits[ClrIndex]!=0 )
{
ColorHits[PalCounts] = ColorHits[ClrIndex]; //由于ClrIndex>=PalCounts,故可以这样赋值
ColorIndex[PalCounts]=ClrIndex; //注意调整相应的索引值
PalCounts++; //颜色数加
}
}
//排序,从大到小,标准的冒泡排序
for (int i = 0; i < PalCounts-1; i++)
{
for (int j = i + 1; j < PalCounts; j++)
{
if (ColorHits[j] > ColorHits[i]) // 把大的值排到前面
{
DWORD dwTmp = ColorHits[i];
ColorHits[i] = ColorHits[j];
ColorHits[j] = dwTmp;
//注意调整相应的索引值
dwTmp = ColorIndex[i];
ColorIndex[i] = ColorIndex[j];
ColorIndex[j] = (WORD)dwTmp;
}
}
}
//为新的调色板分配内存
//RGBQUAD pRGB[256]; // 临时的颜色表信息,后面要用到
for (int i = 0; i < 256; i++)
{
//由位索引值得到R,G,B的最高位值
pRGB[i].rgbRed=(BYTE)((ColorIndex[i] & 0x00f) << 4);
pRGB[i].rgbGreen=(BYTE)((ColorIndex[i] & 0x0f0));
pRGB[i].rgbBlue=(BYTE)((ColorIndex[i] & 0xf00) >> 4);
pRGB[i].rgbReserved =(BYTE)0;
ColorHits[i] = i; //ColorHits作为颜色记数的作用已经完成了,下面的作用是记录位索引值对应的调色板中的索引值
}
//其余的颜色依据最小平方误差近似为前中最接近的一种
long ColorError1,ColorError2;
if (PalCounts > 256)
{
for (int i = 256; i < PalCounts; i++)
{
//ColorError1记录最小平方误差,一开始赋一个很大的值
ColorError1=1000000000;
//由位索引值得到R,G,B的最高位值
long Blue = (long)((ColorIndex[i] & 0xf00) >> 4);
long Green = (long)((ColorIndex[i] & 0x0f0));
long Red = (long)((ColorIndex[i] & 0x00f) << 4);
int ClrIndex = 0;
for (int j = 0; j < 256; j++)
{
//ColorError2计算当前的平方误差
ColorError2=(long)(Blue - pRGB[j].rgbBlue)*
(Blue - pRGB[j].rgbBlue)+ (long)(Green - pRGB[j].rgbGreen)*
(Green - pRGB[j].rgbGreen)+
(long)(Red - pRGB[j].rgbRed)*
(Red - pRGB[j].rgbRed);
if (ColorError2 < ColorError1)
{ //找到更小的了
ColorError1 = ColorError2;
ClrIndex = j; //记录对应的调色板的索引值
}
}
//ColorHits记录位索引值对应的调色板中的索引值
ColorHits[i] = ClrIndex;
}
}
//匹配24位的颜色信息,并把调色板索引写入8位图里
BYTE* pDstBits = dstBits+iPaletteSize;//指向目标位图调色板后
for(int y=0; y<height; y++)
{
BYTE* lpBits=srcBits+y*lLineBytes24;
for(int x=0,n=0; x<lLineBytes24; )
{
int Blue = (int)(*(lpBits+x)&0xf0); //只取高四位
x++;
int Green = (int)(*(lpBits+x)&0xf0);
x++;
int Red = (int)(*(lpBits+x)&0xf0);
x++;
//拼成一个位整数
int ClrIndex=(Blue<<4)+Green+(Red>>4);
for (int i = 0; i < PalCounts; i++)
{
if (ClrIndex == ColorIndex[i])
{
//根据索引值取得对应的调色板中的索引值
*pDstBits = (unsigned char)ColorHits[i];//写入目标位图
*(pDstBits+ lLineBytes8*y + n) = (unsigned char)ColorHits[i];//写入目标位图
n++;
break;
}
}
}
}
//8位BMP的信息头
BITMAPINFOHEADER bi;
bi.biBitCount=8;
bi.biClrImportant=0;
bi.biClrUsed=0;
bi.biCompression=0L;
bi.biHeight=Height();
bi.biPlanes=1;
bi.biSize=sizeof(BITMAPINFOHEADER);
bi.biSizeImage=Height()*lLineBytes8;
bi.biWidth=Width();
bi.biXPelsPerMeter=0;
bi.biYPelsPerMeter=0;
SetBitmapinfoAndBits(bi, dstBits);
CString FileName;
strFileName.Delete(strFileName.GetLength()-4, 4);
FileName.Format("%s的8位图.bmp",strFileName);
//调用保存文件函数
SaveFile(FileName);
//收尾清除指针内存
//free(srcBits);
srcBits = NULL;
free(dstBits);
dstBits = NULL;
AfxMessageBox("已经转换成8位图,另存为:"+FileName);
}
- 24位转8位位图,不是灰度,有颜色的,尽量减少失真
- 24位位图转8位灰度图
- 24位位图转成8位灰度位图
- 24位真色位图转化为8位灰度位图
- 24位真彩色位图转换成8位灰度图片的代码实现
- bmp位图文件:读取、写入、24位真彩转8位灰度、灰度图的二值化
- C++实现24位位图的灰度化
- 24位真彩色位图和8位灰度位图相互转换(C语言实现)
- 仅对8位,24位图像进行灰度处理
- 24位位图转化为灰度图
- 8位位图和24位位图的相互转换
- BMP的8位位图转换24位位图
- c# 24位图像转8位灰度图像(数组方式)
- 【数字图像】C++8位和24位BMP位图的平滑、锐化、二值化处理,以及24位真彩图的灰度化
- C++8位和24位bmp位图平滑、锐化和二值处理,24位真彩图的灰度化
- 24位真彩色图像转8位灰度图像
- 24位真彩图转8位灰度图
- C# 24位彩图转8位灰度图
- UDP课本例题partA
- UDP课本例题partB
- 8位位图转换成24位位图
- UDP实验课01
- 24位位图转成8位灰度位图
- 24位转8位位图,不是灰度,有颜色的,尽量减少失真
- 前面文章里的其他函数,由于这几个函数不是自己写的,所以……
- 坚持学习
- 《草根》创刊号发布——积累是一种态度
- 如何学习Linux
- MyEclipse6.6 汉化过程
- Hibernate的那些事-manyToOne注解映射(Map集合)
- 4月21日
- 相关文章: 中文搜索引擎