关于24位bmp图像转换成8位bmp的问题

fs_you 2011-04-14 10:21:06
我写了一个将24位bmp图像转换成8位bmp的小程序,不过转换结果不对,想了很久一直没想明白,特向各位大牛请教
bool ImageReader::depthfrom24to8(char *newimageName)
{
//以二进制写的方式打开文件

FILE *fp=fopen(newimageName,"wb");

if(fp==0) return 0;

//灰度图像8位深度
int newbiBitCount=8;
//待存储图像数据每行字节数为4的倍数
int lineByte=(imagewidth * newbiBitCount/8+3)/4*4;
//为新图像申请空间
unsigned char *ptempimageBuf=new unsigned char[lineByte*imageheight];
if(!ptempimageBuf)
return 0;



for(int i=0;i<imageheight;i++) //color change from 24 to 8 bit
{
for(int j=0,k=0;j<imagewidth;j++)
{

int B=*(pimageBuf+i*lineByte+3*j+0);
int G=*(pimageBuf+i*lineByte+3*j+1);
int R=*(pimageBuf+i*lineByte+3*j+2);

ptempimageBuf[i*lineByte+j]=(BYTE)(R*0.299 + G*0.587 + B*0.114);
}
}




//颜色表大小,以字节为单位,灰度图像颜色表为1024字节,彩色图像颜色表大小为0
int colorTablesize=1024;



//申请位图文件头结构变量,填写文件头信息

BITMAPFILEHEADER fileHead;

fileHead.bfType = 0x4D42;//bmp类型

//bfSize是图像文件4个组成部分之和

fileHead.bfSize= sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)

+ colorTablesize + lineByte*imageheight;

fileHead.bfReserved1 = 0;

fileHead.bfReserved2 = 0;

//bfOffBits是图像文件前3个部分所需空间之和

fileHead.bfOffBits=54+colorTablesize;

//写文件头进文件

fwrite(&fileHead, sizeof(BITMAPFILEHEADER),1, fp);

//申请位图信息头结构变量,填写信息头信息

BITMAPINFOHEADER head;

head.biBitCount=newbiBitCount;

head.biClrImportant=0;

head.biClrUsed=0;

head.biCompression=0;

head.biHeight=imageheight;

head.biPlanes=1;

head.biSize=40;

head.biSizeImage=lineByte*imageheight;

head.biWidth=imagewidth;

head.biXPelsPerMeter=0;

head.biYPelsPerMeter=0;

//写位图信息头进内存

fwrite(&head, sizeof(BITMAPINFOHEADER),1, fp);

//灰度图像,有颜色表,写入文件
RGBQUAD colortable[256];
for (int i=0;i<256;++i)
{
colortable[i].rgbBlue=i;
colortable[i].rgbGreen=i;
colortable[i].rgbRed=i;
colortable[i].rgbReserved=0;
}
RGBQUAD* pColorTable1=colortable;
fwrite(pColorTable1, sizeof(RGBQUAD),256, fp);


//写位图数据进文件

fwrite(ptempimageBuf, imageheight*lineByte, 1, fp);

//关闭文件

fclose(fp);

delete []ptempimageBuf;
return 1;

}
以下是生成的8位bmp

原图
...全文
904 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
fs_you 2011-04-15
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 photosshop 的回复:]
for(int i=0;i<imageheight;i++) //color change from 24 to 8 bit
{
for(int j=0,k=0;j<imagewidth;j++)
{

int B=*(pimageBuf+i*lineByte+3*j+0);
int G=*(pimageBuf+i*lineByte+3*j+1);
int R=*(pimage……
[/Quote]

明白了 谢谢啊 o(︶︿︶)o 我真是愚蠢到家了
PhotosShop 2011-04-15
  • 打赏
  • 举报
回复
for(int i=0;i<imageheight;i++) //color change from 24 to 8 bit
{
for(int j=0,k=0;j<imagewidth;j++)
{

int B=*(pimageBuf+i*lineByte+3*j+0);
int G=*(pimageBuf+i*lineByte+3*j+1);
int R=*(pimageBuf+i*lineByte+3*j+2);

ptempimageBuf[i*lineByte+j]=(BYTE)(R*0.299 + G*0.587 + B*0.114);
}
}

pimageBuf是24位的彩色图像的地址吧, int B=*(pimageBuf+i*lineByte+3*j+0); 这句你想访问点(I,J)处像素的Blue分量,可你用的是8位的lineByte 啊。 还不明白吗?


fs_you 2011-04-15
  • 打赏
  • 举报
回复
嗯,谢谢!我还是希望能将自己的那段代码改正确!
[Quote=引用 10 楼 winning11xuhao 的回复:]
void CDibView::OnPreprogray() //成功实现调色板
{
// TODO: Add your command handler code here
//获取文档指针
CDibDoc* pDoc=GetDocument();

//原图像颜色数
LPSTR lpSrcDIB;
WORD SrcDIBNumColors;
lpSrcDIB=(LPSTR)::G……
[/Quote]
fs_you 2011-04-15
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 zyrr159487 的回复:]
LZ显示图片的代码也贴一下看看
[/Quote]

原来还要先弄到空间。

我这样就能显示图片啊,只是显示不正确
fs_you 2011-04-15
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 photosshop 的回复:]
唉,8位和24位的lineByte值能相同吗?
[/Quote]

我的lineByte值并不相同啊,不知道你是从哪里看出相同?
winning11xuhao 2011-04-15
  • 打赏
  • 举报
回复
void CDibView::OnPreprogray() //成功实现调色板
{
// TODO: Add your command handler code here
//获取文档指针
CDibDoc* pDoc=GetDocument();

//原图像颜色数
LPSTR lpSrcDIB;
WORD SrcDIBNumColors;
lpSrcDIB=(LPSTR)::GlobalLock( pDoc->GetHDIB());
SrcDIBNumColors=::DIBNumColors(lpSrcDIB);
//真彩图绘图变换
if(SrcDIBNumColors==0)
{
int GrayDIBNumColors=256;
//point to dib
//原图像彩色图像 dib 对象指针和 灰度图像像素指针
LPSTR lpSrcDIBBits;
LPSTR lpGrayDIB;
LPSTR lpGrayDIBBits;
LPBITMAPINFO lpSrcbitmapInfo;
BITMAPINFOHEADER GrayDIBbmiHdr;
//global handle
HDIB hGrayDIB;
//原彩色图像的 dib 和像素指针赋值
lpSrcDIBBits=::FindDIBBits( lpSrcDIB );
//DIB infomation
lpSrcbitmapInfo=( LPBITMAPINFO )lpSrcDIB;
int DIBWidth = lpSrcbitmapInfo->bmiHeader.biWidth;
int DIBHeight=lpSrcbitmapInfo->bmiHeader.biHeight;
//图像字节每行 宽度
long SrcDIBLineBytes= (DWORD)( WIDTHBYTES(
lpSrcbitmapInfo->bmiHeader.biBitCount * DIBWidth) );
long GrayDIBLineBytes=(DWORD)( WIDTHBYTES(
8 * DIBWidth) );
//图像的所占缓冲区的大小 彩色和灰度不同
DWORD SrcDIBSize;
DWORD GrayDIBSize;
SrcDIBSize=(DWORD )(sizeof(BITMAPINFOHEADER) +
(DWORD) SrcDIBLineBytes* DIBHeight);
GrayDIBSize=(DWORD )(sizeof(BITMAPINFOHEADER) +
GrayDIBNumColors * sizeof (RGBQUAD)+
(DWORD) GrayDIBLineBytes * DIBHeight);


//创建灰度DIB内存区
//获取句柄
hGrayDIB= (HDIB)::GlobalAlloc(GHND , GrayDIBSize);
if(NULL==hGrayDIB)
{
MessageBox("分配内存失败!");
return;
}
//获得对象指针
lpGrayDIB = (LPSTR)::GlobalLock(hGrayDIB);
//信息结构指针LP
LPBITMAPINFO lpGraybitmapInfo;
lpGraybitmapInfo = ( LPBITMAPINFO )lpGrayDIB;
//赋值信息结构
memcpy((char*)&GrayDIBbmiHdr,(char*)lpSrcDIB,sizeof(BITMAPINFOHEADER));
GrayDIBbmiHdr.biBitCount = 8;
GrayDIBbmiHdr.biClrUsed = 256;
//赋值GrayDIB图像的BITMAPINFOHEADER
memcpy((char*)lpGrayDIB,(char*)&GrayDIBbmiHdr,sizeof(BITMAPINFOHEADER));
//赋值颜色表项
for(int num=0; num<256; num++)
{
lpGraybitmapInfo->bmiColors[num].rgbBlue = num;
lpGraybitmapInfo->bmiColors[num].rgbGreen = num;
lpGraybitmapInfo->bmiColors[num].rgbRed= num;
lpGraybitmapInfo->bmiColors[num].rgbReserved = 0;
}
//灰度图象素数据指针首地址
lpGrayDIBBits = (char*)lpGrayDIB + sizeof(BITMAPINFOHEADER) +
GrayDIBNumColors*sizeof(RGBQUAD);
//源象素数据大小
DWORD SrcDIBBitSize = SrcDIBLineBytes*DIBHeight;
//灰度图象素数据大小
DWORD GrayDIBBitSize = GrayDIBLineBytes*DIBHeight;
//各自 像素地址
LPSTR lpSrcDIBBits_Pixel;
LPSTR lpGrayDIBBits_Pixel;
int RedV,GreenV,BlueV;
float YV;
BYTE GrayV;
for(int iV=0; iV<DIBHeight; iV++)
{
lpSrcDIBBits_Pixel=(char *)lpSrcDIBBits+(iV*SrcDIBLineBytes);
lpGrayDIBBits_Pixel=(char *)lpGrayDIBBits+(iV*GrayDIBLineBytes);
for(int iH=0; iH<DIBWidth; iH++)
{
RedV = (unsigned char )(*(lpSrcDIBBits_Pixel++));
GreenV= (unsigned char )(*(lpSrcDIBBits_Pixel++));
BlueV = (unsigned char )(*(lpSrcDIBBits_Pixel++));
//变换灰度
YV=(float)(RedV*0.299+GreenV*0.587+BlueV*0.114);
GrayV=(BYTE)YV;
GrayV = (unsigned char) GrayV;
*(lpGrayDIBBits_Pixel++)= (GrayV > 255 ? 255: GrayV);
}
}
::GlobalUnlock(pDoc->GetHDIB());
::GlobalFree(pDoc->GetHDIB());
/*RGBQUAD* pRGBQUAD;
pRGBQUAD = (RGBQUAD*) (lpGrayDIB + sizeof(BITMAPINFOHEADER) );*/
HPALETTE hPal=NULL;
//logical palette handle
LPLOGPALETTE lpPal;
//CPalette* lpDestGrayPal;
HANDLE hLogPal;
hLogPal = ::GlobalAlloc(GHND, sizeof(LOGPALETTE) +
sizeof(PALETTEENTRY)*GrayDIBNumColors);
if(NULL == hLogPal)
return;
//逻辑调色板指针赋值
lpPal = (LPLOGPALETTE) GlobalLock (hLogPal);
lpPal->palVersion= PALVERSION;
lpPal->palNumEntries = GrayDIBNumColors;
/*LPSTR lpSrcDIBBits_Pixel;
DWORD SrcDIBBitSize = SrcDIBLineBytes*DIBHeight;*/
//设置灰度调色板
for(int i=0; i<GrayDIBNumColors; i++)
{
lpPal->palPalEntry[i].peRed=
(unsigned char )i;;
lpPal->palPalEntry[i].peBlue=
(unsigned char )i;
lpPal->palPalEntry[i].peGreen=
(unsigned char )i;
lpPal->palPalEntry[i].peFlags=0;
}
::GlobalUnlock(hLogPal);
::GlobalFree(hLogPal);
pDoc->ReplaceHDIB(hGrayDIB);
//创建调色板并获得其句柄 全局句柄
hPal = ::CreatePalette(lpPal);

if(!hPal)
{
//api全局函数 cwnd
HDC hDC = ::GetDC(CWnd::GetSafeHwnd() );
::SelectPalette(hDC, hPal,TRUE);
::RealizePalette(hDC);
::ReleaseDC(CWnd::GetSafeHwnd() , hDC);
}
pDoc->SetModifiedFlag(TRUE);
pDoc->UpdateAllViews(NULL);
/*::GlobalUnlock(pDoc->m_hDIB);
//::GlobalFree( pDoc->m_hDIB );
//pDoc->m_hDIB = hDIB;*/
}
//CreatDIBPalette( hGrayDIB );*/
BeginWaitCursor();
if(ConvertRGBToGray(( HDIB )::GlobalLock( pDoc->GetHDIB() ), 256))
{
pDoc->SetModifiedFlag(TRUE);
pDoc->UpdateAllViews(NULL);
}
else
{
// 提示用户
MessageBox("分配内存失败!", "系统提示" , MB_ICONINFORMATION | MB_OK);
return;
}
EndWaitCursor();
::GlobalUnlock((HGLOBAL) pDoc->GetHDIB());
}

这段是好使的24转8位的 LZ看一下吧
zyrr159487 2011-04-15
  • 打赏
  • 举报
回复
LZ显示图片的代码也贴一下看看
zyrr159487 2011-04-15
  • 打赏
  • 举报
回复
你要上传图片到你的空间,然后复制图片的属性里的地址,再插入图片,就能显示了
PhotosShop 2011-04-15
  • 打赏
  • 举报
回复
唉,8位和24位的lineByte值能相同吗?
fs_you 2011-04-15
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 gongdiwudu 的回复:]
24bit --->8 bit

需要R取高3位,G取高2位,B取高两位,这样一来构成的图就成了3+2+3依然8位,明白?
[/Quote]

没有明白,我转成的8位是灰度图像,跟3,2,2好像没什么关系吧?
fs_you 2011-04-15
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 gordon3000 的回复:]
看不见你的图。
代码没看出什么问题,pimageBuf这个来源数据没问体吧。
先把调色板去掉看看灰度图出来不,一步步试。
[/Quote]

pimageBuf没问题,因为24位的图我保存下来能正常显示,转成8位后也有图像,不过图像看起来是原图像中的某部分重复了3遍
我不知道怎么上传本地图像,好像那个插入图片不行
副组长 2011-04-15
  • 打赏
  • 举报
回复
哦,解决了。
副组长 2011-04-15
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 fs_you 的回复:]
引用 3 楼 gordon3000 的回复:
看不见你的图。
代码没看出什么问题,pimageBuf这个来源数据没问体吧。
先把调色板去掉看看灰度图出来不,一步步试。


pimageBuf没问题,因为24位的图我保存下来能正常显示,转成8位后也有图像,不过图像看起来是原图像中的某部分重复了3遍
我不知道怎么上传本地图像,好像那个插入图片不行
[/Quote]
一行重复3遍那是一行使用了3行的数据。
biBitCount也已经改成8了,怎没还会出3块呢。水平重复3次,上下重复不?
这样不好找错,实在不行你单独做个8bit的同样大小的位图比一下。
无水先生 2011-04-15
  • 打赏
  • 举报
回复
24bit --->8 bit

需要R取高3位,G取高2位,B取高两位,这样一来构成的图就成了3+2+3依然8位,明白?
副组长 2011-04-15
  • 打赏
  • 举报
回复
看不见你的图。
代码没看出什么问题,pimageBuf这个来源数据没问体吧。
先把调色板去掉看看灰度图出来不,一步步试。
fs_you 2011-04-14
  • 打赏
  • 举报
回复
怎么没有人回复呢 自己再顶一下
fs_you 2011-04-14
  • 打赏
  • 举报
回复
好像图像显示不出来 我也不知道为什么 那个插入图片好像不行

19,468

社区成员

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

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