说到基于GPU的图像处理和实时滤镜,大家肯定会想到鼎鼎大名的GPUImage,这个项目确实为后续开发提供了很多方便,基本的图像处理工具一应俱全。IOS版的项目比较活跃,Android的好像已经被遗弃好久了,一堆bug没人解决。但是学习借鉴GPUImage的项目结构,可以为我们提供不小的帮助。
GPUImage项目结构
GPUImage的项目结构其实很简单,Android版本就更是简陋,结构如下:
- 一堆滤镜(shader以及配套设置参数的代码)
- FilterGroup(利用FBO进行同一副图像的多次处理)
- EGL管理类(主要用来做离屏渲染)
虽然GPUImage的主要价值在那堆滤镜上,但是我们主要来分析后面两个,这是GPUImage的框架,而滤镜就像插件一样,想插就插:D,我们也可以依葫芦画瓢定制自己的滤镜。
为什么要离屏渲染
离屏渲染的主要目的是在后台处理数据,做过Camera应用的都知道,如果用SurfaceView进行预览,那么就不得不把相机数据显示出来,为了不显示,就要把SurfaceView缩到很小,麻烦又浪费资源。Android 3.0后有了SurfaceTexture和GLSurfaceView,之后又有了TextureView,可以自由处理相机数据不显示出来了,但是依然有一个显示和绘制的过程。换句话说,TextureView和GLSurfaceView还不够听话,不能完成我们的所有要求。
如果我们只是想要利用GPU处理一张图片,但是不把他显示出来呢?
举个栗子
我们来看一下Camera360 Lite版的界面:
这些图片都是打开以后选择滤镜就能看到的,不用联网也可以,他们是APK自带的吗?为什么都是同一个人呢?
然而找了一圈以后,我只能在APK中找到这些:
不同颜色的大姐姐去哪了?
这就说明,这些不同的滤镜效果,其实是APK在第一次运行时,在用户手机上生成的。(可以自行查看Camera360 的data文件夹)
这样有很多好处呀,例如说大大减小了APK体积,同一套代码还可以用来完成不同的功能等。
当然,这只是离屏渲染的一个优点。
之前使用GLSurfaceView时,GLSurfaceView帮我们完成了EGL的环境配置,现在不使用GLSurfaceView,我们就要自行管理了,看看GPUImage是怎么做的吧:
GPUImage参考了GLSurfaceView,自己进行了OpenGL的环境配置(好像什么都没说啊,逃…
后面我们在分析GLSurfaceView的代码时,会再来说离屏渲染应该怎么做(毕竟环境配置什么的都是套路)
滤镜组与帧缓存对象(FBO)
GPUImage的滤镜组可以说是对这些滤镜的最好复用。借助于FrameBufferObject(FBO,帧缓存),我们可以在一幅图像上使用不同的滤镜组合来得到想要的结果。
再举个栗子:
我写了一个灰度滤镜,可以把图片转成黑白效果,代码如下:
precision mediump float;
varying vec2 vTextureCoord;
uniform sampler2D sTexture;
void main() {
vec3 centralColor = texture2D(sTexture, vTextureCoord).rgb;
gl_FragColor = vec4(0.299*centralColor.r+0.587*centralColor.g+0.114*centralColor.b);
}
有一天我闲的没事干,又写了一个反色滤镜:
precision mediump float;
varying vec2 vTextureCoord;
uniform sampler2D sTexture;
void main() {
vec4 centralColor = texture2D(sTexture, vTextureCoord);
gl_FragColor = vec4((1.0 - centralColor.rgb), c