Flash显示灰度图像

来源:互联网 发布:怎样注册淘宝会员 编辑:程序博客网 时间:2024/04/29 09:45

有时候可能想在Flash中描述灰度图像或者将彩色图像显示成部分灰色,如果在图像处理软件中处理后再输出到Flash中就显得太麻烦而且应用不够灵活。掌握了灰度图像的处理方法,可以在Flash中将彩色图片的部分区域或整个图像以灰度显示。原理其实很简单,就是将图像的每个像素设置成 R = G = B 。但对图像的每个像素进行操作开销是巨大的,想想一个图片可能几十万个像素,每个像素轮流计算一遍,如果还要以动画的形式渐变,那计算量就更可观了!所以问题的关键就是如何高效的实现这个过程。

                           Flash显示灰度图像

Flash显示灰度图像

Flash显示灰度图像

 

将彩色图像变成灰度图像通常有三种RGB表示形式。

一、最大值法:即分别设置每个像素的 R = G =  B = Max(R,G,B) 。

二、平均值法:即分别设置每个像素的 R = G =  B = (R+G+B)/3  。

三、加权平均值法:即分别设置每个像素的 R = G =  B = ωrR + ωgG + ωbB  ,其中 ωrωgωb分别为R G B分量的权值 。ωrωgωb 分别取不同的值可形成不同的灰度效果,但提示一点,人眼对R G B 的敏感程度不同,对绿色的敏感度最强、红色次之、蓝色最弱。所以一般取值 ωr > ωg > ωb 较为合适。其中ωr = 30% ωg = 59% ωb = 11% 时最感觉最舒适。

而以上三种方法当中,第一种处理结果图像的亮度稍微会大一点,第三种加权平均值法看起来会最舒适!

 

了解了基本方法之后再使用ActionSript对以上的方法进行实现。查看帮助文档中的flash.diaplay.BitmapData类我们可以看到其中定义的很多方法,通常可以通过getPixel、setPixel等相关方法对像素进行操作,即遍历每一个像素分别进行读取-操作-写入;另一种方法可以通过getVector、setVetor方法,getVector(rect:Rectangle):Vector.<uint> 返回的是一个像素的uint值集合,再通过for each...in或for ...in 对集合进行遍历进行读取-操作-写入。可能有人会问,读取之后要怎样操作呢?这样会不会造成很大的cpu负担?就我的初步方法来说,这种手段确实很浪费资源,因为我是先将32为二进制进行分解,得到R G B分量之后比较后再进行组合,然后写入,其中的效率可想而知高不到那里去。那还有其他手段吗?

答案是有的!

 

那就是ColorMatrixFilter滤镜,flash player 提供这个类可以对每个像素进行操作,它避免了我们去分解和组合R G B分量,其内层操作肯定高效得多,并且它使用非常简单!

要用到ColorMatrixFilter滤镜,我们只需设置ColorMatrixFilter类的一个属性即可。 matrix属性  一个4*5数组。 帮住文档中给出了它的计算方法:

redResult   = (a[0]  * srcR) + (a[1]  * srcG) + (a[2]  * srcB) + (a[3]  * srcA) + a[4]
    greenResult = (a[5]  * srcR) + (a[6]  * srcG) + (a[7]  * srcB) + (a[8]  * srcA) + a[9]
    blueResult  = (a[10] * srcR) + (a[11] * srcG) + (a[12] * srcB) + (a[13] * srcA) + a[14]
    alphaResult = (a[15] * srcR) + (a[16] * srcG) + (a[17] * srcB) + (a[18] * srcA) + a[19]

ColorMatrixFilter颜色矩阵滤镜将每个源像素分离成它的红色、绿色、蓝色和 Alpha 成分,分别以 srcR、srcG、srcB 和 srcA 表示。若要计算四个通道中每个通道的结果,可将图像中每个像素的值乘以转换矩阵中的值。(可选)可以将偏移量(介于 -255 至 255 之间)添加到每个结果(矩阵的每行中的第五项)中。 滤镜将各颜色成分重新组合为单一像素,并写出结果。如何设置这个属性呢?

var matrix:Array = new Array();
    matrix = matrix.concat([1, 0, 0, 0, 0]); // red
    matrix = matrix.concat([0, 1, 0, 0, 0]); // green
    matrix = matrix.concat([0, 0, 1, 0, 0]); // blue
    matrix = matrix.concat([0, 0, 0, 1, 0]); // alpha

var filter:ColorMatrixFilter = new ColorMatrixFilter(matrix);然后可以对BitmapData对象通过applyFilter()应用滤镜。


 

接下来将给出上面三种方法的实现:

一、最大值法:(对每个像素分别操作)

function MaxGray(source:BitmapData,rect:Rectangle=null):void
{
 if(rect==null) rect = source.rect ;
 var vector:Vector.<uint> = source.getVector(rect);
 var r:uint,g:uint,b:uint,i:int;
 for each(var color:uint in vector)
 {
   r= Math.max((color&0xff0000)>>16,(color&0xff00)>>8,color&0xff);
   color = 0xff000000 ;
   color |= r;
   color |= (r<<8) ;
   color |= (r<<16) ;
   vector[i++] = color ;
 }
 
 source.setVector(rect,vector);
 trace(getTimer());
}

以上的计算同样可以应用平均值法和加权平均法。将r= Math.max((color&0xff0000)>>16,(color&0xff00)>>8,color&0xff)改动一下即可:

//r = (((color&0xff0000)>>16)+((color&0xff00)>>8)+(color&0xff))*0.33333;//平均值法
    //r = (((color&0xff0000)>>16)*0.3+((color&0xff00)>>8)*0.59+(color&0xff)*0.11);//加权平均值法

 

//r = r>128?255:0 ;// 阈值 -------//将这条语句放在以上三种赋值计算的任何一种之后即将图像二值化,得到photoShop中的“阈值”效果,(128只是其中一种选择,可以将其改为0-255之间的任何值,但太小或太大可能导致产生的结果为全白或全黑)。

阈值化后:Flash显示灰度图像

 

二、平均值法:(使用flash player 自带滤镜)

function AveGray1(source:BitmapData,rect:Rectangle=null):void
{var average:Number = 0.333333 ;
 var matrix:Array = new Array();
 matrix = matrix.concat([average,average,average,0,0]);
 matrix = matrix.concat([average,average,average,0,0]);
 matrix = matrix.concat([average,average,average,0,0]);
 matrix = matrix.concat([0,0,0,0,0]);
 
 var filter:ColorMatrixFilter = new ColorMatrixFilter(matrix);
 if(rect==null)  rect = source.rect ;

source.applyFilter(source,rect,new Point(),filter);
 trace(getTimer());
}

 

三、加权平均值法:(与平均值法类似)

function WeiGray(source:BitmapData,rect:Rectangle=null):void
{
 var matrix:Array = new Array();
 matrix = matrix.concat([0.3,0.59,0.11,0,0]);
 matrix = matrix.concat([0.3,0.59,0.11,0,0]);
 matrix = matrix.concat([0.3,0.59,0.11,0,0]);
 matrix = matrix.concat([0,0,0,0,0]);
 
 var filter:ColorMatrixFilter = new ColorMatrixFilter(matrix);
 if(rect==null) rect = source.rect ;
 source.applyFilter(source,rect,new Point(),filter);
 trace(getTimer());
}

    通过 trace(getTimer()) ,你可以比较各种方法的执行效率,我的测试结果:780*670像素的图片,第一种方法用时达到450毫秒,第二种、第三种基本可以保持在150毫秒以内。我的机器配置比较低,这里只是想说明两种方法的执行效率的差别!
   所以在处理图像时,应尽可能使用flash player内置的方法,但必须提醒,即使是内置的方法,如果对图像连续处理,其资源消耗也是巨大的。

应用ColorMatrixFilter、ColorTransform类可以创造出很炫的效果,但就存在一个缺点,我想不用说了吧!

from:http://blog.sina.com.cn/s/blog_6757f30d0100i0iv.html

原创粉丝点击