
If I could find a document about GPUImage in Chinese, I would have not so much troubles when I learnt how to use it. But recently I noticed there are several people has translated the wiki of GPUImage in GitHub to Chinese already. So for this post, I just pick some important points up from it and explaining in my own ideas. Therefore, I cannot translate this post in English LOL. BTW, the cover is the one of works created by the application with GPUImage as well, and this pic is used for celebrating the Chinese Monkey Year.
Overview
GPUImage可以对图片、摄像头实时影像、视频添加通过GPU加速的滤镜和图像处理效果。
与iOS5.0上的CoreImage框架比较,GPUImage的优势:可以自定义滤镜(通过自定义glsl语句来实现);不足:没有人脸检测等此类先进技术(话说现在已经相对不先进了吧。。)。
如果需要对图片或者视频进行大量计算,那么GPU实现可以说是首选,iPhone4上比较快了100倍。
使用GPU处理图像需要编写大量代码才可实现,作者就先写了一篇demo(http://www.sunsetlakesoftware.com/2010/10/22/gpu-accelerated-video-processing-mac-and-ios)。之后发现其实之间有很多可模版化的内容,再结合具体使用,最后开发出了GPUImage。意思就是使用GPUImage可以实现基于OpenGLES2.0的GPU处理图像工作并且基本不需涉及OpenGLES2.0的api。
Technical requirements
iOS5+,ARC,有摄像头,…现在已经不存在不满足要求的吧。
General architecture
这个在第一篇当中已经大致说明我自己的理解,此处就照本翻译。
GPUImage是通过OpenGL ES 2.0着色器实现图片和视频的处理计算,所以会比CPU更快。并且!在使用过程中不需要涉及复杂的OpenGLES2.0的api,而是提供封装好的OC实现的类和方法即可实现图片或视频的多步骤处理操作、并能导出处理完成的结果。
视频或图片载入后会以GPUImageOutput的一种子类为类型的资源对象存在。GPUImage具备的资源类有:GPUImageVideoCamera、GPUImageStillCamera、GPUImagePicture、GPUImageMovie(我记得还有一种:GPUImageRawDataInput。具体使用之后细说)。资源对象会把图片或视频载入到纹理(OpenGLES中的一种存储图片信息的具体对象),并且把这些纹理传入具体的处理流程。
在整个处理流程链中的滤镜或者说除了输入源之后的对象,都需要遵循GPUImageInput协议,只有这样才能拿到上一个步骤处理完成的纹理进行相应处理。这些对象会经过预先设置好的所有目标对象中,并且处理过程中可以有多个分支的存在,即有多个下一步骤的路径。
总结:通过GPUImage可以创建一个滤镜链,链中可以有多个分支,载入所需输入源后经过每个步骤的处理可得到一个或者多个结果。
Performing common tasks(挑重点)
Filtering live video
通过CustomShader.fsh(glsl语句构成)文件作为参数生成的自定义滤镜customFilter可以作为一个目标(target)添加到从摄像头获取到的实时影像帧对象上。最终,这些经过滤镜处理后的帧内容会显示在一个继承自UIView并且可以把纹理显示出来的视图(GPUImageView,其实最终是通过它的layer,即CAEAGLLayer对象来展示)上。
接下来提到了一个重点:GPUImageView的fillMode属性。源码中该属性的每个枚举都有简短的解释:1.kGPUImageFillModeStretch, // Stretch to fill the full view, which may distort the image outside of its normal aspect ratio。拉伸内容至填满整个视图,可能会照成图片被不等比拉伸至变形。
2.kGPUImageFillModePreserveAspectRatio, // Maintains the aspect ratio of the source image, adding bars of the specified background color。保持显示图片的原比例,在未铺满区域显示设置的背景颜色。
3.kGPUImageFillModePreserveAspectRatioAndFill // Maintains the aspect ratio of the source image, zooming in on its center to fill the view。保持显示图片的原比例,等比放大填充整个视图并居中显示。
这个fillMode在我实际项目中给我带来了一些困扰。所以这里就先简单翻译,想在之后单独针对GPUImageView的文章中详细说明。
如果想在通过GPUImage录制视频时也把声音录进去,那么可以设置GPUImageVideoCamera对象的audioEncodingTarget属性。
Capturing and filtering a still photo
这里提到的一点是:在某些设备上是支持不到2048或者更高像素的摄像头图片捕捉,原因是这些设备对纹理大小有相应的限制,翻开源码,可以从继承自GPUImageOutput的五个资源类中发现,初始化资源将信息写入纹理时,会做一次资源文件大小的判断。因为对应生成的纹理对象是根据资源文件大小来生成的,所以如果过大,则会使用当前设备所支持的最大纹理大小来进行生成。纹理既然作为一个编辑过程中实时存储数据信息的对象,它也是会占据相应内存的,并且在处理过程中,如果纹理过大,或者说纹理中待处理的信息过多,也会给GPU带来压力。所以即使在使用GPUImage对图片或者视频进行处理的过程中,同样需要注意处理资源的大小问题。
Processing a still image
对一张静态图片进行滤镜或者其他效果处理可以说是GPUImage的基础入门操作(我是这么认为)。
1.使用GPUImagePicture的初始化方法,可以将一张静态图片载入到纹理中。不过GPUImagePicture的初始化方法有好几个,具体区别同样之后再细说。
2.可以通过继承自GPUImageFilter的类的对象调用imageFromCurrentFramebuffer方法得到处理后的图片。但如果要使用这种方法导出图片,则必须要在GPUImagePicture对象执行processImage方法之前执行滤镜对象的useNextFrameForImageCapture方法,否则按照GPUImage的源码来看注定会crash,控制台的提示“Tried to overrelease a framebuffer, did you forget to call -useNextFrameForImageCapture before using -imageFromCurrentFramebuffer?”。
3.另一种导出处理图片的方法是调用滤镜对象的imageByFilteringImage方法,入参为UIImage对象。
Writing a custom filter
GPUImage相比CoreImage另一个大优势在于可以自定义滤镜,通过glsl语言(OpenGL Shading Language,十分类似C语言的OpenGL着色器语言)实现。GPUImage库中的绝大多数滤镜都是通过自定义的glsl语句进行对片段着色器操作,之前也有说过,因为大多数滤镜只改变纹理内容,并不会涉及到如何贴图,或者说如何展示纹理。
Filtering and re-encoding a movie
视频文件通过GPUImageMovie类载入,GPUImageMovieWriter类导出。需要注意的点有:
1.记录,或者说处理完成后,需要将GPUImageMovieWriter对象从上一个target(一般都为GPUImageFilter对象)中移除,并且调用自身的finishRecording方法。
2.如果在记录完成前坏了,那之前的处理导出内容也没了。
Interacting with OpenGL ES
通过GPUImage的GPUImageTextureOutput和GPUImageTextureInput类,可以从OpenGLES中导入或者导出纹理。使用这种方式的过程中要注意,待处理的纹理需要通过类似共享群组的东西在GPUImage自身的OpenGLES的context和其他context之间实现共享。
Built-in filters
GPUImage库中提供125种左右的内建滤镜。
这个我记得网上已经有大神对文档中有说明的滤镜做了详细的翻译,之后会针对比较常用或者特殊的滤镜做详细说明,此处就不翻译了。
Sample applications
又想起第一次接触GPUImage时,不看文档直接download,run,完了完全不知道每个demo的具体实现内容。所以建议初学者在接触到新的三方库或者源码时,不要急着run,先看看文档或者源码注释,可能会更好上手。
1.SimpleImageFilter:对一张静态图片进行滤镜操作,保存到disk。
2.SimpleVideoFilter:马赛克录像,滑杆可调整马赛克颗粒大小。
3.SimpleVideoFileFilter:对disk中的视频文件进行虚化处理,并保存为另一个视频文件。
4.MultiViewFilterExample:摄像头实时滤镜效果,多个滤镜叠加,并且其中两个是自定义滤镜。
5.FilterShowcase:GPUImage内建滤镜的全部展示,这个demo中的判断语句优点复杂。
6.BenchmarkSuite:GPUImage与基于CPU实现的图片处理效果以及CoreImage做的处理效率比较。
7.CubeExample:说明GPUImage与OpenGLES渲染的相互关系。给摄像头获取到的每一帧内容加上sepia(乌贼色效果?)的滤镜并且显示在一个立方体的表面,可以用手机旋转立方体。立方体被渲染成一个texture-backed(没懂)的frambuffer对象,再反馈给GPUImage进行马赛克处理后显示。
7.ColorObjectTracking:待解释。
I’ll translate the contents later.