中秋月圆时一个关于位图处理的问题(特邀季老大加入)

灯火斑斓 2003-09-12 02:00:54
我的项目遇到一个位图处理的问题,平时主要开发数据库,图像处理第一次遇,请各位高手,特别是想请季老大帮忙指导指导.
问题描述,先把位图处理成单色位图(1bit);然后从图片的第一列开始扫描,把第一至第八个像素读取出来放到一个Byte中,即Pix[0][0]放到B0,Pix[0][1]放到B1,Pix[0][2]放到B3,以此类推;读完第一列前八个像素后,再读第二列前八个像素,同样的处理,读完一个Width循环后,再读第一列9至16个像素(若未足8个像素则补零)以此类推直至读完本幅图的像素.因为处理完的文件是给单片机的液晶显示屏用的,所以要求在读原始位图的像素时,要按白-1,黑-0的方式来处理,也就是说放到B0-B7的值就只能是0,1;我现在是通过提取每个像素的颜色RGB数值来判断的,直觉告诉我这有问题.下面是我的源码,请高手赐教.非常感谢!

int iLen,iCount,iWidth,iHeight,iData;
int iFrom,iTo;
long lData;
int R,G,B;
TColor Clr;

FILE *fp;
fp=fopen("123.bmp","wb");
if(fp==NULL)
{
ShowMessage("Logo图片保存文件创建失败!");
return false;
}

AnsiString sFileName="abc.bmp";
if(FileExists(sFileName))
{
Graphics::TBitmap *tmpBitmap = new Graphics::TBitmap();
tmpBitmap->LoadFromFile(sFileName);
tmpBitmap->PixelFormat=pf1bit;
tmpBitmap->SaveToFile("tmp.bmp");
tmpBitmap->LoadFromFile("tmp.bmp");
iWidth=tmpBitmap->Width;
iHeight=tmpBitmap->Height;
lData=iWidth; //本幅图片的宽度
if(!DecToHex(lData))
{
Char[0]=1;Char[1]=0;Char[2]=0;Char[3]=0;
}
sStr = AnsiString((char)(int)Char[2])+AnsiString((char)(int)Char[1])+AnsiString((char)(int)Char[0]);
fwrite(sStr.c_str(),sStr.Length(),1,fp);
lData=iHeight; //本幅图片的高度
if(!DecToHex(lData))
{
Char[0]=1;Char[1]=0;Char[2]=0;Char[3]=0;
}
sStr = AnsiString((char)(int)Char[2])+AnsiString((char)(int)Char[1])+AnsiString((char)(int)Char[0]);
fwrite(sStr.c_str(),sStr.Length(),1,fp);
iTo=0;
iCount=0;
while(true)
{
if(iTo>=iHeight) {break;}
for(int i=0;i<iWidth;i++)
{
iFrom=8*iCount;
iTo=8*(iCount+1);
if(iTo>iHeight)
{
sStrTmp="";
for(int j=iFrom;j<iHeight;j++)
{
Clr=tmpBitmap->Canvas->Pixels[i][j];
R=(Clr>>16)&0xff;
G=(Clr>>8)&0xff;
B=Clr&0xff;
if(R<5&&G<5&&B<5)
sStrTmp ="0"+sStrTmp;
else
sStrTmp ="1"+sStrTmp;
}
for(int i=iHeight+1;i<=iTo;i++)
sStrTmp ="0"+sStrTmp;
}
else
{
sStrTmp="";
for(int j=iFrom;j<iTo;j++)
{
Clr = tmpBitmap->Canvas->Pixels[i][j];
R=(Clr>>16)&0xff;
G=(Clr>>8)&0xff;
B=Clr&0xff;
if(R<5&&G<5&&B<5)
sStrTmp ="0"+sStrTmp;
else
sStrTmp ="1"+sStrTmp;
}
}
iData=BINStrToChar(sStrTmp); //把二进制字符串转换成十进制数
sStr=AnsiString((char)iData);
fwrite(sStr.c_str(),sStr.Length(),1,fp);
}
iCount++;
sStr="";
}
delete tmpBitmap;
}
}
fclose(fp);
...全文
48 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
灯火斑斓 2003-09-14
  • 打赏
  • 举报
回复
我的问题搞定了,关键在位图二值化上.再次谢谢weibz0525(小虫)和季老大
灯火斑斓 2003-09-12
  • 打赏
  • 举报
回复
季老大,见笑了.
你说对了,这个输出文件的格式是给单片机显示图片用的(因此后缀名可任意),格式有些特别,它需要把单色位图中第一列第一至八个像素放到一个Byte中(因此不能用ScanLine来读取像素)再写入文件中,然后再分别读取第二列,第三列...(至第Width列)第一至八个像素读出后同上操作. 一个循环后再从每列的第9至16这八个像素读出作同样的处理,即是每列均读取连续的八个像素,到最后不足八个像素的补零即可.但在像素处理时并不是简单的照搬,要按像素的颜色值按白1黑0的二值放入B0-B7中.
报歉,季老大,不知我的描述您是否已经明白.请多多包涵.
jishiping 2003-09-12
  • 打赏
  • 举报
回复
虽然读取图像点的次序不一样,但是如何读取图像中的点的方法是一样的。如果楼主要通过
Canvas->Pixels[i][j] 来得到每个点的颜色,就根本没有必要先将图形转换为1bit。转换
为1bit后,没有必要先保存为文件然后再从文件读取。至于楼主保存的文件格式,明明不是
bmp文件,可是后缀名却偏偏为.bmp,不知道楼主是什么意思。至于楼主保存的文件格式,那
是楼主自己定义的,后面的代码(将图像点数据转换为sStrTmp)就不好说是正确的还是错误
的了。

说了半天就是:楼主的代码,只能说有很多不合理的地方。因为最后保存的数据格式是楼主
自己定义的,所以保存的结果是否正确(就是后面的代码是否正确),无人知道。
灯火斑斓 2003-09-12
  • 打赏
  • 举报
回复
谢谢weibz0525(小虫),我大概明白你的意思,因为要处理的原始位图可能不是单色,我先用二值化处理,而且我现在取像素的方式和你的不一样,我先试试先.Thanks!
weibz0525 2003-09-12
  • 打赏
  • 举报
回复
原始位图是单色的吗?如果不是先要二值化图象转化为单色位图
单色位图的象素在图象数据存储时候每个只占一位,也就是说一个字节能存储八个象素深度。
采取从高到低的原则,也就是,
7 6 5 4 3 2 1 0
0 1 2 3 4 5 6 7
不知道你明不明白,这个我作过,有源码你可以参考一下。
我也曾蒙季老大指导过:)
int m, n;
BYTE* ptr;
Graphics::TBitmap* tBitmap ;
tBitmap=new Graphics::TBitmap();
tBitmap->LoadFromFile(OpenImageEnDialog1->FileName);
ImageWidth=tBitmap->Width;
ImageHeight=tBitmap->Height;
ImageDataWidth=(tBitmap->Width+31)/32*4*8;
ImageData=new char[ImageHeight*ImageDataWidth];
char *p=ImageData;
for (int y = 0; y < ImageHeight; y++)
{
ptr = (Byte *)tBitmap->ScanLine[y];
for (int x = 0; x < ImageDataWidth/8; x++)
for(int z=7;z>=0;--z)
p[y*ImageDataWidth+x*8+7-z]=(ptr[x]&(1<<z))?1:0;
}

delete []ImageData;
delete tBitmap;
灯火斑斓 2003-09-12
  • 打赏
  • 举报
回复
谢谢weibz0525(小虫)和季老大,我马上去验证.
jishiping 2003-09-12
  • 打赏
  • 举报
回复
“应该如何判定是白色(1)或黑色(0)呢?”

其实上面 weibz0525(小虫) 给的代码里已经包含了你要的取像素点的代码。对于单色的
Bitmap,点(X,Y)的颜色是白色还是黑色的,用下面的代码判断:
if (((BYTE*)Bitmap->ScanLine[Y])[X/8] & (1<<(7-X/8)))
; //(X,Y) 为白色
else
; //(X,Y) 为黑色
灯火斑斓 2003-09-12
  • 打赏
  • 举报
回复
谢谢weibz0525(小虫)提供的资料,我也知道应该先有图像处理的基础知识后再进行相关开发,但往往都是书到用时方恨少的感觉.
季老大的说法是对的,第一行的像素放在低位.有感于老大说的"谁说不可以用ScanLine来读取像素?"(爬键盘格子的人应该要冲破某些思维定势),你虽然没有说明方法,但我大概已经知道了.真是"与君一席话,甚读十年书".关键在于我现在不太明白如何判断原始单色位图的像素,我应该如何判定是白色(1)或黑色(0)呢?
jishiping 2003-09-12
  • 打赏
  • 举报
回复
“把单色位图中第一列第一至八个像素放到一个Byte中”
那么次序呢?第1行放在低位还是高位呢?从你的代码来看,是第1行放在最低位,第8行
放在最高位。

“因此不能用ScanLine来读取像素”
谁说不可以用ScanLine来读取像素?一样可以的!使用Canvas->Pixels[i][j]取像素是最慢
的方法。
weibz0525 2003-09-12
  • 打赏
  • 举报
回复
ScanLine也就是找到图象数据部分的指针,进行读取数据部分的操作。
你 既然知道,当然就可以不用他,直接用指针读取图象数据就可以了。
看你数据的格式,应该和普通的单色存储的格式差不多,
如果不是从高到底存储的,你可以将我上面的程序z循环改为从0到7就可以了。
给你个网站,先看看里面的基础部分,会有收获的
http://www.pris.edu.cn/imgprocess/theory/subject.htm

13,825

社区成员

发帖
与我相关
我的任务
社区描述
C++ Builder相关内容讨论区
社区管理员
  • 基础类社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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