如果你使用过Photoshop这样的图像处理工具,一定曾为它们各式各样的图形处理方式兴奋不已吧?不过话说回来,它也仅仅能处理单幅的静止图像。如果有一种方法能让你在自己编写的应用程序中加入类似Photoshop中的图像处理功能,而且是经过改进的动态特技处理手段,你会觉得怎么样呢?有兴趣的话就请继续往下看。
在介绍这些特技处理方法之前,让我们先做一些技术约定:用C++Builder开发工具编写,应用ScanLine处理技术(可极大提升图像处理速度)。如果您用的不是C++Builder开发工具也没关系,先看懂下面的处理方法后再将处理函数做一些修改,即可以应用到您喜欢的开发工具中去。
特技一、模糊淡出效果
也许您对淡入淡出效果较为熟悉,但对一边淡出一边模糊的效果一定感到新鲜吧!
首先分别谈谈淡出与模糊效果的原理。淡出函数的原理很简单,就是将每一像素点的R、G、B颜色值减去相同的整数直至零,这样即可实现整幅图的暗化。模糊函数相对要复杂一些,因为必须考虑周围像素的影响,这就要引入加权算法,按照给定的系数对周围像素点和当前点的颜色值进行加权运算。
下面让我们参考范例。在C++Builder中创建新的工程(窗体保存为test.cpp),在Form中加入一个Image控件、一个Timer控件和一个Button控件。把Image控件的Autosize属性改为 True,Visible属性改为False,Align属性改为alClient,把Timer控件的Enable属性改为 False,Interval属性改为10,把Button控件的Caption属性改为“观看淡出模糊效果并且退出”,其他的都采用默认属性。
打开test.h头文件,在其中加入淡出函数和模糊函数的声明:
void softdowncolor(TImage *Bp,int step); //淡出函数
void softflt(TImage *Bp); //模糊函数
其中,淡出函数softdowncolor的step参数是在淡出时减掉的颜色值,你可以通过它来控制淡出的速率。
接着,在test.cpp文件中加入淡出函数和模糊函数的实现:
void softdowncolor(TImage *Bp,int step)
{ BYTE *ptr;
int i,j;
int color;
Bp->Picture->Bitmap->PixelFormat=pf24bit;
for(i=0;iHeight;i++){
ptr=(BYTE *)Bp->Picture->Bitmap->ScanLine[i];
for(j=0;jWidth*3;j+=3){
color=ptr[j+2];
color-=step;
if(color<0)color=0;
ptr[j+2]=color;
color=ptr[j+1];
color-=step;
if(color<0)color=0;
ptr[j+1]=color;
color=ptr[j];
color-=step;
if(color<0)color=0;
ptr[j]=color;
}
}
}
void softflt(TImage *Bp)
{ int Div=100;
int temp[3];
int flt[9]={10,10,10,10,20,10,10,10,10};
BYTE *ptr,*ptru,*ptrm,*ptrd;
int i,j,k,m;
Bp->Picture->Bitmap->PixelFormat=pf24bit;
for(k=1;k<(Bp->Picture->Bitmap->Height-1);k++){
ptr=(BYTE *)Bp->Picture->Bitmap->ScanLine[k];
ptrm=(BYTE *)Bp->Picture->Bitmap->ScanLine[k];
ptru=(BYTE *)Bp->Picture->Bitmap->ScanLine[k-1];
ptrd=(BYTE *)Bp->Picture->Bitmap->ScanLine[k+1];
for(m=3;m<(Bp->Picture->Width-1)*3;m+=3){
temp[0]=0;
temp[1]=0;
temp[2]=0;
for(i=-1;i<=1;i++)
for(j=0;j<3;j++)
temp[j]+=ptrm[m+3*i+j]*flt[4+i];
for(i=-1;i<=1;i++)
for(j=0;j<3;j++)
temp[j]+=ptru[m+3*i+j]*flt[1+i];
for(i=-1;i<=1;i++)
for(j=0;j<3;j++)
temp[j]+=ptrd[m+3*i+j]*flt[7+i];
for(i=0;i<3;i++){
temp[i]=temp[i]/Div;
if(temp[i]>255)temp[i]=255;
if(temp[i]<0)temp[i]=0;
ptr[m+i]=temp[i];
}
}
}
}
现在让我们看看实际效果吧!在test.cpp中定义一全局变量:int BeEnd;
并且响应Form的创建事件:
void __fastcall TForm1::FormCreate(TObject *Sender)
{ Image1->Picture->LoadFromFile("1.bmp"); //加载的图像文件必须是Bmp格式
}
双击Button控件添加按钮响应事件:
void __fastcall TForm1::Button1Click(TObject *Sender)
{ BeEnd=0;
Timer1->Enabled=true;
}
双击Timer控件添加定时器响应事件:
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{ BeEnd++;
softflt(Image1);
softdowncolor(Image1,20);
this->Canvas->CopyRect(Rect(0,0,Image1->Picture->Width, Image1->Picture->Height),Image1->Canvas,Rect(0,0,Image1->Picture->Width, Image1->Picture->Height));
if(BeEnd>=12){
Timer1->Enabled=false;
Close();
}
}
编译运行程序,你就可以看到如图1和图2所示的模糊淡出效果。
特技二、透明图层动态切换
透明图层动态切换的核心是定义一个透明函数。透明函数的原理是将前景图像和背景图像相同位置上的像素的颜色按照一定系数进行比较取值,计算公式为:
COLOR=color2*DV+color2*(1-DV)
其中DV为小于等于1并且大于等于0的小数。
让我们看看具体的编程。跟上面一样,创建一个新的工程,不过这回一共要添加三个Image控件,Align属性全部都是alClient。把Button控件的Caption属性修改成 “观看透明图层动态切换效果”。打开test.h头文件,在其中加入透明函数的声明:
void changepic(TImage *mg1,TImage *mg2,TImage *mg3,int div);
图1 图2
mg1、mg2、mg3分别是前景图像、背景图像、缓冲图像,div是透明系数,为0到100间的整数。
在test.cpp文件中加入透明函数的实现部分:
void changepic(TImage *mg1,TImage *mg2,TImage *mg3,int div)
{ BYTE *ptr1,*ptr2,*ptr3;
int i,j,tmp;
mg3->Canvas->CopyRect(Rect(0,0,mg1->Picture->Width,mg1-> Picture->Height),mg1->Canvas,Rect(0,0,mg1->Picture->Width,mg1-> Picture->Height));
mg1->Picture->Bitmap->PixelFormat=pf24bit;
mg2->Picture->Bitmap->PixelFormat=pf24bit;
mg3->Picture->Bitmap->PixelFormat=pf24bit;
for(i=0;iPicture->Height;i++){
ptr1=(BYTE *)mg1->Picture->Bitmap->ScanLine[i];
ptr2=(BYTE *)mg2->Picture->Bitmap->ScanLine[i];
ptr3=(BYTE *)mg3->Picture->Bitmap->ScanLine[i];
for(j=0;jPicture->Width*3;j+=3){
tmp=ptr1[i*3+j]*div/100+ptr2[i*3+j]*(100-div)/100;
ptr3[i*3+j]=tmp;
tmp=ptr1[i*3+j+1]*div/100+ptr2[i*3+j+1]*(100-div)/100;
ptr3[i*3+j+1]=tmp;
tmp=ptr1[i*3+j+2]*div/100+ptr2[i*3+j+2]*(100-div)/100;
ptr3[i*3+j+2]=tmp;
}
}
}
在test.cpp中定义一全局变量:int test;
为Form增添创建时的响应事件:
void __fastcall TForm1::FormCreate(TObject *Sender)
{ Image1->Picture->LoadFromFile("1.bmp");
Image3->Picture->LoadFromFile("1.bmp");
Image2->Picture->LoadFromFile("2.bmp");
}
双击Button控件添加按钮响应事件:
void __fastcall TForm1::Button1Click(TObject *Sender)
{ test=0;
Timer1->Enabled=true;
}
双击Timer控件添加定时器响应事件:
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{ test+=3;
if(test<=100){
changepic(Image2,Image1,Image3,test);
this->Canvas->CopyRect(Rect(0,0,Image3->Picture->Width, Image3->Picture->Height),Image3->Canvas,Rect(0,0,Image3-> Picture->Width,Image3->Picture->Height));
}
else Timer1->Enabled=false;
}
编译并运行程序,点击Button1就可以看到两幅透明的图在互相切换,如图3、图4、图5所示。
程序在Borland C++ Builder 5、Windows98下调试通过。