GPUImage详细解析(四)模糊图片处理
回顾
解析(一)
解析(二)
解析(三)
这次介绍的GPUImageContext
、GPUImageFramebufferCache
和GPUImagePicture
。
GPUImageContext
GPUImageContext是GPUImage对OpenGL ES上下文的封装,添加了GPUImage相关的上下文,比如说Program的使用缓存,处理队列,CV纹理缓存等。
1、属性介绍
contextQueue
统一处理队列
currentShaderProgram
正在使用的program
context
OpenGL ES的上下文
coreVideoTextureCache
CV纹理缓存
framebufferCache
GPUImageBuffer缓存
shaderProgramCache
Program的缓存
shaderProgramUsageHistory
Program的使用历史
2、方法介绍
-
useAsCurrentContext()
在useAsCurrentContext设置当前上下文的时候,会先判断上下文是否是当前context,不是再设置(为了避免上下文切换的性能消耗,即使设置的上下文是同一个上下文也会消耗性能) -
sizeThatFitsWithinATextureForSize()
会调整纹理大小,如果超过最大的纹理,会调整为不超过最大的纹理宽高。 -
(GLProgram*)programForVertexShaderString:fragmentShaderString:;
shaderProgramCache 是program的缓存,由顶点shader和片元shader字符串拼接起来做key。 -
- (void)useSharegroup:(EAGLSharegroup *)sharegroup;
EAGLSharegroup类管理一个或者多个EAGLContext的OpenGLES资源;这个是一个封闭的类,没有开发者API。负责管理纹理缓存、顶点缓存、帧缓存、颜色缓存。(textures, buffers, framebuffers, and render buffers) -
- (EAGLContext *)context;
返回OpenGL ES2.0的上下文,同时设置glDisable(GL_DEPTH_TEST);
,图像处理管道默认不允许使用深度缓存。
GPUImageFramebufferCache
GPUImageFramebufferCache是GPUImageFrameBuffer的管理类
1、属性介绍
CacheframebufferCache
缓存字典
framebufferTypeCounts
缓存数量字典
activeImageCaptureList
正在读取Image数据的GPUImageFrameBuffer列表
framebufferCacheQueue
缓存队列
2、方法介绍
-
- (NSString *)hashForSize: textureOptions:onlyTexture:;
根据size、textureOptions和onlyTexture,创建缓存字符串。
缓存字符串+当前缓存数量形成framebufferCache缓存的key。
如果找不到framebufferCache对应的数量,会创建新的缓存。 -
- (void)returnFramebufferToCache:;
回收缓存。根据size、textureOptions和onlyTexture,创建缓存字符串,缓存字符串+当前缓存数量形成framebufferCache缓存的key。(之所以会加上数量,是因为缓存字符串不唯一) -
- (void)addFramebufferToActiveImageCaptureList:;
- (void)removeFramebufferFromActiveImageCaptureList:
这两个方法主要用于,当newCGImageFromFramebufferContents()
读取帧缓存图像数据时,保持GPUImageFramebuffer的引用。并且读取完数据后,在dataProviderUnlockCallback()
方法释放。
GPUImagePicture
GPUImagePicture是PGUImage的图像处理类,继承GPUImageOutput,一般作为响应链的源头。
1、属性介绍
pixelSizeOfImage 图像的像素大小。
hasProcessedImage 图像是否已处理。
imageUpdateSemaphore 图像处理的GCD信号量。
2、方法介绍
-
- (id)initWithCGImage:smoothlyScaleOutput:
用源图像newImageSource和是否采用mipmaps来初始化GPUImagePicture。
如果图像大小超过OpenGL ES最大纹理宽高,或者使用mipmaps,或者图像数据是浮点型、颜色空间不对等都会采用CoreGraphics重新绘制图像。
然后通过glTexImage2D把图像数据发送给GPU,最后释放掉CPU的图像数据。 -
- (BOOL)processImageWithCompletionHandler:;
通知targets处理图像,并在完成后调用complete代码块。在处理开始时,会标记hasProcessedImage为YES,并调用dispatch_semaphore_wait()
,确定上次处理已经完成,否则取消这次处理。
-
- (void)addTarget: atTextureLocation:;
添加target到响应链。如果hasProcessedImage为YES,表示图像已经处理完毕,直接设置targets的InputSize,并调用newFrameReadyAtTime()
通知target。
DEMO
用GPUImagePicture处理源图像,用GPUImageTiltShiftFilter处理模糊效果,用GPUImageView显示。
效果展示
核心代码
将GPUImageView设置为self.view,根据face.png,设置GPUImagePicture,然后添加GPUImageTiltShiftFilter到响应链,再把GPUImageView作为响应链的终点,最后调用processImage,开始处理图像。
GPUImageView *primaryView = [[GPUImageView alloc] initWithFrame:self.view.frame];
self.view = primaryView;
UIImage *inputImage = [UIImage imageNamed:@"face.png"];
_sourcePicture = [[GPUImagePicture alloc] initWithImage:inputImage];
_sepiaFilter = [[GPUImageTiltShiftFilter alloc] init];
_sepiaFilter.blurRadiusInPixels = 40.0;
[_sepiaFilter forceProcessingAtSize:primaryView.sizeInPixels];
[_sourcePicture addTarget:_sepiaFilter];
[_sepiaFilter addTarget:primaryView];
[_sourcePicture processImage];
总结
最近因为直播用户增长太快,忙着优化原来的逻辑,研读源代码的时间变少。
同时为了写这篇文章,查了一些关于图像资料,末尾附上。
下一篇文章可能会介绍今年大火的直播APP的一种速成方案,也可能会是GPUImageMovie的介绍。
喜欢的点一下关注,不迷路。
Mipmap纹理技术是目前解决纹理分辨率与视点距离关系的最有效途径,它会先将图片压缩成很多逐渐缩小的图片,例如一张6464的图片,会产生6464,3232,1616,88,44,22,11的7张图片,当屏幕上需要绘制像素点为2020 时,程序只是利用 3232 和 1616 这两张图片来计算出即将显示为 2020 大小的一个图片,这比单独利用 32*32 的那张原始片计算出来的图片效果要好得多,速度也更快.
kCGImageAlphaLast:alpha 分量存储在每个像素中的低位,如RGBA。
kCGImageAlphaFirst:alpha 分量存储在每个像素中的高位,如ARGB。
kCGImageAlphaPremultipliedLast:alpha 分量存储在每个像素中的低位,同时颜色分量已经乘以了 alpha 值。
kCGImageAlphaPremultipliedFirst:alpha 分量存储在每个像素中的高位,同时颜色分量已经乘以了 alpha 值。
kCGImageAlphaNoneSkipLast:没有 alpha 分量。如果像素的总大小大于颜色空间中颜色分量数目所需要的空间,则低位将被忽略。
kCGImageAlphaNoneSkipFirst:没有 alpha 分量。如果像素的总大小大于颜色空间中颜色分量数目所需要的空间,则高位将被忽略。