今天做了彩色图片变灰色及图片变亮的处理。下面就分享下我的做法。
首先,在百度上搜下彩色图片变灰色(黑白),有很多的源码,其中它的原理在于亮度
=0.299R+0.587G+0.114B(具体怎么回事我赞不深究)。对于每个点,让亮度值替换原来的RGB即可。
根据这样的说法,那程序很简单了。我这里采用简易的公式 亮度=(3R+6G+B)/10。在程序的目录下
有个big.bmp文件(24位,就是用附件图画生成的那种),要生成的灰色文件为bigbmp2.bmp.以下是C语
言程序。
#include<stdio.h>
main()
{
//以下变量有可能有些是不需要的,没有做整理
char ch;
unsigned long cntsize=0;
unsigned long datasize=0;
unsigned int offset=0xffff;
unsigned char offset0,offset1,offset2,offset3;
unsigned char bits=0;
unsigned char width=0,height=0;
unsigned char datap[1000][3];
unsigned int i,k;
unsigned char widthsmall=0,heightsmall=0;
unsigned char widthbig=0,heightbig=0;
unsigned char datapbig[10000][3];//采用的例子big.bmp文件很小,大小不超过100*100,所以这里就定义了一个数组来存放bmp数据
unsigned char filehead[100];
unsigned char gray,maxgray;
unsigned long sumgray;
FILE *inf, * outftxt, * outfbmp;
cntsize=0;
datasize=0;
offset=0xffff;
if((inf=fopen("big.bmp","r"))==NULL)
{
printf("cant open source file!");
goto loopexit;
}
if((outfbmp=fopen("bigbmp.bmp","w"))==NULL)
{
printf("cant open target file!");
goto loopexit;
}
//以下这段是读big.bmp好知道长宽颜色数据在哪里开始之类,了解的同志可以略过
while(!feof(inf))
{
ch=fgetc(inf);
if(cntsize==0x02)printf(" filesize:");
else if(cntsize==0x0a)printf(" offset:");
else if(cntsize==0x0e)printf(" offset=%x ",offset);
else if(cntsize==0x12)printf(" width:");
else if(cntsize==0x16)printf(" height:");
else if(cntsize==0x1a)printf("width=%d height=%d ",width,height);
else if(cntsize==0x1c)printf(" bits:");
else if(cntsize==offset)printf(" offset start: ");
printf("%2x ",(unsigned char)ch);
if(datasize>1){if(datasize%3==2)printf(" ");}
else{filehead[cntsize]=(unsigned char)ch;}
datapbig[datasize/3][datasize%3]=(unsigned char)ch;
if(cntsize==0x0a)offset0=(unsigned char)ch;
else if(cntsize==0x0b)offset1=(unsigned char)ch;
else if(cntsize==0x0c)offset2=(unsigned char)ch;
else if(cntsize==0x0d)
{
offset3=(unsigned char)ch;
offset=(((unsigned int)offset1)<<8)|(((unsigned int)offset0));
}
else if(cntsize==0x12)offset0=(unsigned char)ch;
else if(cntsize==0x13)offset1=(unsigned char)ch;
else if(cntsize==0x14)offset2=(unsigned char)ch;
else if(cntsize==0x15)
{
offset3=(unsigned char)ch;
width=(((unsigned int)offset1)<<8)|(((unsigned int)offset0));
}
else if(cntsize==0x16)offset0=(unsigned char)ch;
else if(cntsize==0x17)offset1=(unsigned char)ch;
else if(cntsize==0x18)offset2=(unsigned char)ch;
else if(cntsize==0x19)
{
offset3=(unsigned char)ch;
height=(((unsigned int)offset1)<<8)|(((unsigned int)offset0));
}
else if(cntsize==0x1c)bits=(unsigned char)ch;
cntsize++;if(cntsize>offset){datasize++;}
fputc(ch,outfbmp);
}
fclose(inf);
fclose(outfbmp);
printf("\n data:\n");
for(i=0;i<(datasize/3);i++)
{
for(k=0;k<3;k++)
{
printf("%x ",datapbig[i][k]);
}
printf(" ");
}
widthsmall=width,heightsmall=height;
//以上bmp文件头部放在filehead[i]里,数据放在datapbig[i][k]里面 ,点个数为datasize
//sumgray为所有亮度之和,maxgray为最亮的点的亮度,这段是为了后面的提高亮度准备的,对于只是要转成灰色图片的同志略过
sumgray=0;maxgray=0;
for(i=0;i<(datasize/3);i++)
{
//得到当前点的亮度,这里R为datapbig[i][2]
gray=(((unsigned int)datapbig[i][0])*1+((unsigned int)datapbig[i][1])*6+((unsigned int)datapbig[i][2])*3)/10;
if(gray>maxgray)maxgray=gray;
sumgray=sumgray+gray;
}
//写灰色到bigbmp2.bmp中
if((outfbmp=fopen("bigbmp2.bmp","w"))==NULL)
{
printf("cant open target file!");
goto loopexit;
}
for(i=0;i<offset;i++)
{
fprintf(outfbmp,"%c",filehead[i]);
//fprintf(outfbmp,"%c",1);
}
for(i=0;i<(datasize/3);i++)
{
gray=(((unsigned int)datapbig[i][0])*1+((unsigned int)datapbig[i][1])*6+((unsigned int)datapbig[i][2])*3)/10;
//gray=gray*255/maxgray;//这句话如果不隐掉则能提高此灰色图片的对比度,即较暗的灰色变白
for(k=0;k<3;k++)
fprintf(outfbmp,"%c",gray);//灰色数据写到bigbmp2.bmp中
}
fclose(outfbmp);
printf("i love frog");
loopexit:
;
}
下面说下灰色图片提高对比度,我这里说的不是人家标准的对比度的意思,如果big.bmp整体颜色都很
灰暗,那我怎么才能看清楚这幅图呢?我只需把稍微亮的点变成较亮的点就可以了,而原来黑色点还是
保持黑色就可以了。比如说我检测到整幅图的最亮的点值为0x30,比较亮的点值为0x20,那我想把最亮的
点值提高到0xff,那么较亮的点提高为 0x20*0xff/0x30;所以只要把上面的程序
中//gray=gray*255/maxgray;的双斜杠去掉就可以了。当然,不是一定要最亮点非要提高到0xff,提高的
值自己可以改成自己的喜欢的。
刚才说的是灰色图片提高对比度的问题,那彩色图片呢?我搜了下百度,我好像没有看到统一的一个说
法,所以我这里就用最简单的方法,RGB每个颜色提高同样的比值,既写数据那段改成如下:
for(i=0;i<(datasize/3);i++)
{
for(k=0;k<3;k++)
{
//在函数开头定义了databigfinite为unsigned int型
databigfinite=((unsigned int)datapbig[i][k])*200/maxgray;//这里假使最亮的点亮度为200,不是上面举例的255
if(databigfinite>255)databigfinite=255;//如果R或G或B大于255,就简单处理为255
datapbig[i][k]=databigfinite;
fprintf(outfbmp,"%c",datapbig[i][k]);
}
}
通过实验效果还行,但是对于图片的由深到浅的红色一块效果就不好了,究其原因是因为当RGB中一个值提高大于255就简单的当做255处理了事了。那如何解决这个问题呢?我们可以用个简单的办法下了解下这个问题的本质。
看附件图画里选择颜色双击会有具体的颜色条,比如红色,那个颜色条会有RGB分别为255 0 0,如果把颜色往浅色调的话,则GB同时增加值。根据这个原理(其实我不太清楚具体原理啦)在程序中如果R多余255,则把多出来的值平均分给GB。下面是对这段处理的程序(因为编个简洁的程序比较费脑子,我又急于看结果,所以就分成琐碎的好几个 if语句)
for(i=0;i<(datasize/3);i++)
{
for(k=0;k<3;k++)
{
//这个databigfinite[k]代替上面的databigfinite 定义为数组databigfinite[3]
databigfinite[k]=((unsigned int)datapbig[i][k])*200/maxgray;
}
if((databigfinite[0]>255)||(databigfinite[1]>255)||(databigfinite[2]>255))
{
if((databigfinite[0]+databigfinite[1]+databigfinite[2])>3*255)
{
databigfinite[0]=255;databigfinite[1]=255;databigfinite[2]=255;
}
else if((databigfinite[0]>255)&&(databigfinite[1]>255))
{
databigfinite[2]=databigfinite[2]+(databigfinite[0]-255+databigfinite[1]-255);
databigfinite[0]=255;databigfinite[1]=255;
}
else if((databigfinite[0]>255)&&(databigfinite[2]>255))
{
databigfinite[1]=databigfinite[1]+(databigfinite[0]-255+databigfinite[2]-255);
databigfinite[0]=255;databigfinite[2]=255;
}
else if((databigfinite[2]>255)&&(databigfinite[1]>255))
{
databigfinite[0]=databigfinite[0]+(databigfinite[2]-255+databigfinite[1]-255);
databigfinite[2]=255;databigfinite[1]=255;
}
else if(databigfinite[0]>255)
{
databigfinite[1]=databigfinite[1]+(databigfinite[0]-255)/2;
databigfinite[2]=databigfinite[2]+(databigfinite[0]-255)/2;
databigfinite[0]=255;
}
else if(databigfinite[1]>255)
{
databigfinite[0]=databigfinite[0]+(databigfinite[1]-255)/2;
databigfinite[2]=databigfinite[2]+(databigfinite[1]-255)/2;
databigfinite[1]=255;
}
else if(databigfinite[2]>255)
{
databigfinite[1]=databigfinite[1]+(databigfinite[2]-255)/2;
databigfinite[0]=databigfinite[0]+(databigfinite[2]-255)/2;
databigfinite[2]=255;
}
}
for(k=0;k<3;k++)
{
datapbig[i][k]=databigfinite[k];
fprintf(outfbmp,"%c",datapbig[i][k]);
}
}
到这里就OK了。那个由深到浅的色段完全可以看出了。虽然程序很简单,但是自己还是蛮开心的。