我们知道图像都是由一个一个像素组成的,而每一个像素的颜色都由一个RBG值确定,由此组成了一副美丽的图像。
如果我们现在要将一副彩色的图像灰度化,就要对每一个像素点做处理。一般的处理方法是将图片颜色值的RGB三个通道值设为一样,这样原本的256*256*256种颜色就只有256种了,256种颜色值就丢失了图片的彩色信息,留下的只有亮度值,视觉上看上去就是灰色的图片。
灰度处理一般有三种算法:
- 最大值法:即新的颜色值R=G=B=Max(R,G,B),这种方法处理后的图片看起来亮度值偏高。
- 平均值法:即新的颜色值R=G=B=(R+G+B)/3,这样处理的图片十分柔和
- 加权平均值法:即新的颜色值R=G=B=(R * Wr+G*Wg+B*Wb),一般由于人眼对不同颜色的敏感度不一样,所以三种颜色值的权重不一样,一般来说绿色最高,红色其次,蓝色最低,最合理的取值分别为Wr = 30%,Wg = 59%,Wb = 11%
其实知道了上面的算法,图像灰度处理就变得简单了,无非就是循环遍历图像像素,一个一个修改就好了。一张1920*1080的图片,有2073600像素点,如果使用CPU进行遍历无异于大炮打苍蝇出力不讨好。这个时候GPU的并行处理能力就派上用场了,而OpenGL ES又是GPU的驱动,所以OpenGL ES什么时候用我想大家也就明白了。
加权平均值法
我们使用加权平均值法对图片进行灰度化处理,我们拷贝Image
类修改为GrayFilter
,修改片段着色器代码如下
// 灰度片段着色器代码
private final String grayFragmentShaderCode =
"precision mediump float;\n" +
"uniform sampler2D vTexture;\n" +
"varying vec2 aTexCoordinate;\n" +
"void main() {\n" +
" vec4 rgba = texture2D(vTexture, aTexCoordinate);\n" +
" float color = rgba.r * 0.3 + rgba.g * 0.59 + rgba.b * 0.11;\n" +
" gl_FragColor = vec4(color, color, color, 1.0);\n" +
"}\n";
为了使GrayFilter更加通用我们不再内部传入Bitmap生成纹理,而是外部传入纹理进行渲染,修改onDraw
方法如下:
public void onDraw(int textureId, float[] matrix)
我们使用这个灰度滤镜渲染一张1080*2041大图看下,哇哦看着效果确实不错。本人使用测试手机是2018年发布的一加6T,渲染时间不到1ms,可见OpenGL ES
对图像强大的处理能力。