作者:杨丰盛
上一篇我们分析了处理图片特效的原理,通常是将图像数据转换为一个int[]数组,然后再操作这个int[]数组,最后将操作之后的int[]数组转换为一个Image即可。本文我们接着分析另外几种常用特效的实现原理。
负片特效
要在图像处理软件中将图片处理为负片特效,非常简单,但是这些图像处理软件也是通过程序来实现的,其实现原理通常是用255来减去图像数据的r,g,b值,得到一个新的r,g,b值,再将新的数值合成图片即可,具体实现代码如下:
/*
* 图片特效负片
*/
public Image effect_negative(Image src) {
int srcW = src.getWidth();
int srcH = src.getHeight();
int[] srcPixels = getPixels(src);
int r = 0;
int g = 0;
int b = 0;
int a = 0;
int argb;
for (int i = 0; i < srcH; i++) {
for (int ii = 0; ii < srcW; ii++) {
argb = srcPixels[i * srcW + ii];
a = ((argb & 0xff000000) >> 24); // alpha channel
r = 255 - ((argb & 0x00ff0000) >> 16); // red channel
g = 255 - ((argb & 0x0000ff00) >> 8); // green channel
b = 255 - (argb & 0x000000ff); // blue channel
srcPixels[i * srcW + ii] = ((a << 24) | (r << 16) | (g << 8) | b);
}
}
return drawPixels(srcPixels, srcW, srcH);
}
在JavaME中一个像素都是一个int数据,要分别取得其a,r,g,b通道直接使用移位操作即可,如下所示。在其他更复杂的特效处理中夜经常这样来提取一个像素的a,r,g,b数值。
a = ((argb & 0xff000000) >> 24);
r = ((argb & 0x00ff0000) >> 16);
g = ((argb & 0x0000ff00) >> 8);
b = (argb & 0x000000ff);
对于负片特效的演示效果,如下图所示。
黑白特效
图像的黑白特效实现的原理是将图像的a,r,g,b通道的值都降低一定的比例,因此实现过程即为先取出每个像素的a,r,g,b通道数据,然后分别乘以一个颜色的比例(该比例可以根据实际实现进行调整),然后将个通道数据按照((a << 24) | (r << 16) | (g << 8) | b)方式合成一个int值,具体实现代码如下所示。
/*
* 图片特效黑白
*/
public Image effect_black_white(Image src) {
int srcW = src.getWidth();
int srcH = src.getHeight();
int[] srcPixels = getPixels(src);
int r = 0;
int g = 0;
int b = 0;
int a = 0;
int argb;
int temp;
for (int i = 0; i < srcH; i++) {
for (int ii = 0; ii < srcW; ii++) {
argb = srcPixels[i * srcW + ii];
a = ((argb & 0xff000000) >> 24); // alpha channel
r = ((argb & 0x00ff0000) >> 16); // red channel
g = ((argb & 0x0000ff00) >> 8); // green channel
b = (argb & 0x000000ff); // blue channel
temp = (int) (.299 * (double) r + .587 * (double) g + .114 * (double) b);
r = temp;
g = temp;
b = temp;
srcPixels[i * srcW + ii] = ((a << 24) | (r << 16) | (g << 8) | b);
}
}
return drawPixels(srcPixels, srcW, srcH);
}
这里我们对r,g,b通道分别乘了0.299,0.587,0.114,该数值可以进行调整,具体效果如下图所示。
粉笔画特效
粉笔画大家都见得很多了,这里就不作过多的介绍了,要通过程序实现粉笔画的可以通过以下公式进行实现:
R=255-(Math.
sqrt((2*(r-r1)*(r-r1)+(r-r2)*(r-r2))))
G=255-(Math.
sqrt((2*(g-g1)*(g-g1)+(g-g2)*(g-g2))))
B=255-(Math.
sqrt((2*(b-b1)*(b-b1)+(b-b2)*(b-b2))))
其中r1和r2分别为当前像素的右边一个像素和下边一个像素的r值,g1、g2、b1、b2同理。
有关粉笔画的效果具体实现代码如下:
/*
* 图片特效粉笔画
*/
public Image effect_crayon(Image src)
{
int srcW = src.getWidth();
int srcH = src.getHeight();
int[] srcPixels = getPixels(src);
int r = 0;
int g = 0;
int b = 0;
int a = 0;
int argb;
int r1 = 0;
int g1 = 0;
int b1 = 0;
int r2 = 0;
int g2 = 0;
int b2 = 0;
for (int i = 0; i < srcH; i++)
{
for(int ii=0;ii<srcW;ii++)
{
argb = srcPixels[i*srcW+ii];
a = ((argb & 0xff000000) >> 24); // alpha channel
r = ((argb & 0x00ff0000) >> 16); // red channel
g = ((argb & 0x0000ff00) >> 8); // green channel
b = (argb & 0x000000ff); // blue channel
if(i+1 == srcH)
{
r1= 0;
g1= 0;
b1=0;
}
else
{
argb = srcPixels[(i+1)*srcW+ii];
r1 = ((argb & 0x00ff0000) >> 16); // red channel
g1 = ((argb & 0x0000ff00) >> 8); // green channel
b1 = (argb & 0x000000ff); // blue channel
}
if(ii+1 == srcW){
r2= 0;
g2= 0;
b2=0;
}
else
{
argb = srcPixels[i*srcW+ii+1];
r2 = ((argb & 0x00ff0000) >> 16); // red channel
g2 = ((argb & 0x0000ff00) >> 8); // green channel
b2 = (argb & 0x000000ff); // blue channel
}
// rr1=(r1-r2)^2 rr2=(r1-r3)^2
r = (int)Math.sqrt((double)(2*(r-r1)*(r-r1)+(r-r2)*(r-r2)));
g = (int)Math.sqrt((double)(2*(g-g1)*(g-g1)+(g-g2)*(g-g2)));
b = (int)Math.sqrt((double)(2*(b-b1)*(b-b1)+(b-b2)*(b-b2)));
r =255-r; // red channel
g =255-g; // green channel
b =255-b; // blue channel
srcPixels[i*srcW+ii] = ((a << 24) | (r << 16) | (g << 8) | b);
}
}
return drawPixels(srcPixels, srcW, srcH);
}
通过该函数实现的粉笔画效果如下图所示。