Photoshop里的灰度变换可以使R,G,B 3色按任何比例增强再混合,原理和下面的差不多。
黑白图片的黑白变换叫灰度变换,彩色图片的色彩变换也叫灰度变换,PhotoShop里叫色阶变换
一幅彩色图像的象素矩阵中每个象素由RGB 3种颜色按一定的比例混合形成一种颜色来表示,比如黑色使RGB(0,0,0) ,纯红色是RGB(0,1,0)...。在处理相片时,有时可能因为环境光源太暗,使RGB色的值偏小,就会使图形太暗看不清,如果环境光源太光,又使图像泛白,通过灰度变换,就可以使RGB值调和到合适的程度,使相片变得漂亮。
变换原理是这样的:
首先提取一幅图像的一个象素,在BMP格式中一个象素由8位红色亮度值,8位绿色亮度值和8位蓝色亮度值组成,只要按一定的变换函数去变换
这种3种颜色的亮度值就可以起到灰度变换的目的。
比如线性变换
可以用一个线性函数
f(x,y)=a'+(b'-a')/(b-a)×(f(x,y)-a)
f(x,y)代表一个象素
[a,b]是原始图像的灰度范围,[a',b']是变换后新图像的灰度范围
用这个线性函数分别对R,G,B分量进行变换可以起到单色增强的目的,然后再混合输出。
如果b'-a' > b-a ,则使得图像灰度范围增大,即对比度增大,图像会变得清晰
如果b'-a' < b-a ,则使得图像灰度范围缩小,即对比度减小。
分段线性变换
和线性变换差不多
不过对于单一一个R或G或B分量采用分段函数进行变换。
如
f(x,y)=a'+(b'-a')/(b-a)×(f(x,y)-a) 当f(x,y)在[a,b]范围内
f(x,y)=0 当f(x,y)
这样就指定了一个变换段 a,b,只有灰度在a,b段内的点才会增强,灰度b的变成白色。
非线性变换
可以根据需要制定非线性函数对灰度进行变换,典型的有
对数变换
f(x,y)=a+ ln[f(x,y)+1]/(b×lnc) 这里a,b,c是参数而不是灰度范围了,对数变换用于扩展低灰度区
指数变换
f(x,y)=b^(c*[f(x,y)]-a]) ,a,b,c同样是参数,指数变换用来压缩低灰度区
下面用BCB实现一个对256色无压缩BMP图像的灰度变换
//-----------------------------------------BCB6程序----------------------------
#include
#pragma hdrstop
#include
#include "Unit1.h"
#include"File1.h"
#pragma pack(1)//----强制结构用1字节对齐
struct BITMAPFILEHEADER_
{
short type;
int bfSize;
short re1,re2;
int Offbits;
};
struct BITMAPINFO_
{
long size;
long width,height;
short planes,bitCount;
long comp,sizeImg;
long xpels,ypels;
long used,important;
};
//-------------将BMP彩色表的数据校正到BCB TColor的数据。
void SwitchColor(long &c)
{
long blue=c& 0x000000ff;
long green=c& 0x0000ff00;
long red=c& 0x00ff0000;
c=(blue<<16) | green | (red>>16);
}
//---------线性灰度变换,rr,gg,bb为增强系数
void strengthen (long &c,double rr,double gg,double bb)
{
unsigned char r=(c & 0x00ff0000)>>16;
unsigned char g=(c & 0x0000ff00)>>8;
unsigned char b=(c & 0x000000ff);
unsigned char nr;
unsigned char ng;
unsigned char nb;
if(rr*r>255)
nr=255;
else
nr=rr*r;
if(gg*g>255)
ng=255;
else
ng=gg*g;
if(bb*b>255)
nb=255;
else
nb=bb*b;
c=(nr<<16) | (ng<<8) | (nb);
}
void xxx()
{
FILE *f=fopen("F://FX3.bmp","rb");
if(f==NULL) /*判断文件是否打开成功*/
{
ShowMessage("File open error");
return;
}
fseek(f,0,0);//移动到开头
//----------读BMP文件头
BITMAPFILEHEADER_ *bmph=new BITMAPFILEHEADER_();
if(fread((char*)bmph,sizeof(BITMAPFILEHEADER_),1,f)==NULL)
{
ShowMessage("File read error");
return;
}
//-----------读BMP信息头
BITMAPINFO_ *bmpi=new BITMAPINFO_();
if(fread((char*)bmpi,sizeof(BITMAPINFO_),1,f)==NULL)
{
ShowMessage("File read error2");
return;
}
//--------------读彩色表
long *c=new long[bmph->Offbits-sizeof(BITMAPFILEHEADER_)-sizeof(BITMAPINFO_)];
fread((char*)c,bmph->Offbits-sizeof(BITMAPFILEHEADER_)-sizeof(BITMAPINFO_),1,f);
//----------显示一些信息
Form1->Edit1->Text=IntToStr(bmph->bfSize);
Form1->Edit2->Text=IntToStr(bmpi->width);
Form1->Edit3->Text=IntToStr(bmpi->height);
Form1->Edit4->Text=IntToStr(bmpi->comp);
Form1->Edit5->Text=IntToStr(bmpi->used);
//------------显示图形
unsigned char *p=new unsigned char[4];
int i=0,j=0,k=0,wc=0;
TColor *tc;
if(bmpi->width%4==0)//-----------因为BMP图像4字节对齐
wc=bmpi->width/4;
else
wc=bmpi->width/4+1;
for( i=0;i
{
for(j=0;j
fread(p,4,1,f);
for(k=0;k<4;k++)
{
long x=c[p[k]];
//--------这里开始增强色彩
strengthen(x,1.1,1.1,1.5); //1.1 1.1 和1.5 为RGB各分量的增强系数
//---------校正数据
SwitchColor(x);//----------因为BCB的TCOLOR和BMP的彩色表反了。
Form1->Canvas->Pixels[200+j*4+k][300-i]=x; //------200和300是定位到Canvas的中间而已。
}
}
}
fclose(f);
};
对于要进行非线性变换或其他特殊的变换,只需要修改strengthen函数里的变换操作。
经过实际运行,变换效果不过~~~