彩色图片变灰色,图片亮度变暗变亮--图像处理之二

来源:互联网 发布:windows 用户权限控制 编辑:程序博客网 时间:2024/05/18 19:19

   今天做了彩色图片变灰色及图片变亮的处理。下面就分享下我的做法。

  首先,在百度上搜下彩色图片变灰色(黑白),有很多的源码,其中它的原理在于亮度

=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了。那个由深到浅的色段完全可以看出了。虽然程序很简单,但是自己还是蛮开心的。