假设我们自定义一个OpenGL ES程序来处理图片,那么会有以下几个步骤:
1、初始化OpenGL ES环境,编译、链接顶点着色器和片元着色器;
2、缓存顶点、纹理坐标数据,传送图像数据到GPU;
3、绘制图元到特定的帧缓存;
4、在帧缓存取出绘制的图像。
GPUImageFilter
负责的是第一、二、三步。
GPUImageFramebuffer
负责是第四步。
一、GPUImageFilter解析
GPUImageFilter和响应链的其他元素实现了
GPUImageInput
协议,他们都可以提供纹理参与响应链,或者从响应链的前面接收并处理纹理。响应链的下一个对象是target,响应链可能有多个分支(添加多个targets)。
Filters and other subsequent elements in the chain conform to the GPUImageInput protocol, which lets them take in the supplied or processed texture from the previous link in the chain and do something with it. Objects one step further down the chain are considered targets, and processing can be branched by adding multiple targets to a single output or filter.
获取纹理坐标
1
|
+ (const GLfloat *)textureCoordinatesForRotation:(GPUImageRotationMode)rotationMode;
|
绘制结果输出
绘制的结果后输入到
outputframebuffer
指定的缓存
usingNextFrameForImageCapture
代表着输出的结果会被用于获取图像,所以在绘制之前要加锁
1 2 3 4
|
if (usingNextFrameForImageCapture) { [outputFramebuffer lock]; }
|
绑定纹理
glBindTexture(GL_TEXTURE_2D, [firstInputFramebuffer texture]);
绑定输入纹理,OpenGL ES才能确定要处理纹理数据
绑定顶点和纹理坐标并绘制图元
1 2 3
|
glVertexAttribPointer(filterPositionAttribute, 2, GL_FLOAT, 0, 0, vertices); glVertexAttribPointer(filterTextureCoordinateAttribute, 2, GL_FLOAT, 0, 0, textureCoordinates); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
GL_TRIANGLE_STRIP
模式用于绘制三角形带。
这里有介绍
纹理解锁
[firstInputFramebuffer unlock];
输入纹理使用完毕,解锁。在调用这个解锁之前必须确定之前已经调用加锁,否则会报错。
GPUImageFramebuffer
使用引用计数来管理缓存,当引用计数小于0的时候会回收缓存。
信号量
如果设置了
usingNextFrameForImageCapture
,则会通过GCD信号量来通知仍在等待绘制完成的函数。
1 2 3 4
|
if (usingNextFrameForImageCapture) { dispatch_semaphore_signal(imageCaptureSemaphore); }
|
通知targets
- (void)informTargetsAboutNewFrameAtTime:(CMTime)frameTime;
当self的帧绘制完成后,通知自己的targets,并将自己的输出设置为targets的输入纹理:
[self setInputFramebufferForTarget:currentTarget atIndex:textureIndex];
然后解锁自己使用的输出缓冲区
[[self framebufferForOutput] unlock];
(在上一个函数已经lock了这个缓冲区,所以这里的unlock不会马上回收内存,等到targets使用完自己的纹理后调用unlock,缓存会被回收)
在设置完缓冲区后,self会通知所有targets(除了设置忽略的)
[currentTarget newFrameReadyAtTime:frameTime atIndex:textureIndex];
等待渲染完成
1 2 3 4
|
if (dispatch_semaphore_wait(imageCaptureSemaphore, convertedTimeout) != 0) { return NULL; }
|
一系列setter
- (void)setInteger:(GLint)newInteger forUniformName:(NSString *)uniformName;
这些函数是设置GLSL里面的变量
OpenGL ES教程-帧缓存
有提到过。
百度百科的介绍
YUV数据格式-图文详解
GPUImage中的YUV
GLProgram *yuvConversionProgram;
将YUV颜色空间转换成RGB颜色空间的GLSL。
CVPixelBufferGetPlaneCount()
返回缓冲区的平面数。
通过
CVOpenGLESTextureCacheCreateTextureFromImage()
创建两个纹理luminanceTextureRef(亮度纹理)和chrominanceTextureRef(色度纹理)。
convertYUVToRGBOutput()
把YUV颜色空间的纹理转换成RGB颜色空间的纹理
顶点着色器-通用
kGPUImageVertexShaderString
片元着色器:
1、
kGPUImageYUVFullRangeConversionForLAFragmentShaderString
2、
kGPUImageYUVVideoRangeConversionForLAFragmentShaderString
区别在不同的格式
video-range (luma=[16,235] chroma=[16,240])
full-range (luma=[0,255] chroma=[1,255])
SO的详细介绍
琨君
的
基于GPUImage的实时美颜滤镜
对GPUImage实现美颜滤镜的原理和思路做了详细介绍。
本文以
琨君的代码
为demo,结合前两篇解析,探究美颜过程中的GPUImage实现。
基于GPUImage的实时美颜滤镜
中的美颜滤镜,包括
GPUImageBilateralFilter
、
GPUImageCannyEdgeDetectionFilter
、
GPUImageCombinationFilter
、
GPUImageHSBFilter
。
绘制流程图
1、
GPUImageVideoCamera
捕获摄像头图像
调用
newFrameReadyAtTime: atIndex:
通知
GPUImageBeautifyFilter
;
2、
GPUImageBeautifyFilter
调用
newFrameReadyAtTime: atIndex:
通知
GPUImageBilateralFliter
输入纹理已经准备好;
3、
GPUImageBilateralFliter
绘制图像后在
informTargetsAboutNewFrameAtTime()
,
调用
setInputFramebufferForTarget: atIndex:
把绘制的图像设置为
GPUImageCombinationFilter
输入纹理,
并通知
GPUImageCombinationFilter
纹理已经绘制完毕;
4、
GPUImageBeautifyFilter
调用
newFrameReadyAtTime: atIndex:
通知
GPUImageCannyEdgeDetectionFilter
输入纹理已经准备好;
5、同3,
GPUImageCannyEdgeDetectionFilter
绘制图像后,
把图像设置为
GPUImageCombinationFilter
输入纹理;
6、
GPUImageBeautifyFilter
调用
newFrameReadyAtTime: atIndex:
通知
GPUImageCombinationFilter
输入纹理已经准备好;
7、
GPUImageCombinationFilter
判断是否有三个纹理,三个纹理都已经准备好后
调用
GPUImageThreeInputFilter
的绘制函数
renderToTextureWithVertices: textureCoordinates:
,
图像绘制完后,把图像设置为
GPUImageHSBFilter
的输入纹理,
通知
GPUImageHSBFilter
纹理已经绘制完毕;
8、
GPUImageHSBFilter
调用
renderToTextureWithVertices: textureCoordinates:
绘制图像,
完成后把图像设置为
GPUImageView
的输入纹理,并通知
GPUImageView
输入纹理已经绘制完毕;
9、
GPUImageView
把输入纹理绘制到自己的帧缓存,然后通过
[self.context presentRenderbuffer:GL_RENDERBUFFER];
显示到
UIView
上。
-
MIPMAP
Mipmap纹理技术是目前解决纹理分辨率与视点距离关系的最有效途径,它会先将图片压缩成很多逐渐缩小的图片,例如一张64
64的图片,会产生64
64,32
32,16
16,8
8,4
4,2
2,1
1的7张图片,当屏幕上需要绘制像素点为20
20 时,程序只是利用 32
32 和 16
16 这两张图片来计算出即将显示为 20
20 大小的一个图片,这比单独利用 32*32 的那张原始片计算出来的图片效果要好得多,速度也更快.
图像数据格式
kCGImageAlphaLast:alpha 分量存储在每个像素中的低位,如RGBA。
kCGImageAlphaFirst:alpha 分量存储在每个像素中的高位,如ARGB。
kCGImageAlphaPremultipliedLast:alpha 分量存储在每个像素中的低位,同时颜色分量已经乘以了 alpha 值。
kCGImageAlphaPremultipliedFirst:alpha 分量存储在每个像素中的高位,同时颜色分量已经乘以了 alpha 值。
kCGImageAlphaNoneSkipLast:没有 alpha 分量。如果像素的总大小大于颜色空间中颜色分量数目所需要的空间,则低位将被忽略。
kCGImageAlphaNoneSkipFirst:没有 alpha 分量。如果像素的总大小大于颜色空间中颜色分量数目所需要的空间,则高位将被忽略。
图像颜色空间
-
1.
二、GPUImageFramebuffer
-
2.
扩展
-
3.
总结
-
4.
GPUImageVideoCamera
-
4.1.
1、视频图像采集 :AVCaptureSession
-
4.2.
2、颜色空间:YUV
-
5.
3、纹理绘制
-
6.
GPUImageView
-
6.1.
1、填充模式
-
7.
2、OpenGL ES绘制
-
8.
GPUImage类介绍
-
8.1.
1、GPUImageFilterGroup
-
8.2.
2、GPUImageTwoInputFilter
-
8.3.
3、GPUImageThreeInputFilter
-
8.4.
4、GPUImageBeautifyFilter
-
9.
绘制流程
-
10.
总结
-
11.
GPUImageContext
-
11.1.
1、属性介绍
-
11.2.
2、方法介绍
-
12.
GPUImageFramebufferCache
-
12.1.
1、属性介绍
-
12.2.
2、方法介绍
-
13.
GPUImagePicture
-
13.1.
1、属性介绍
-
13.2.
2、方法介绍
-
14.
总结
缺失模块。
1、请确保node版本大于6.2
2、在博客根目录(注意不是yilia根目录)执行以下命令:
npm i hexo-generator-json-content --save
3、在根目录_config.yml里添加配置:
jsonContent:
meta: false
pages: false
posts:
title: true
date: true
path: true
text: false
raw: false
content: false
slug: false
updated: false
comments: false
link: false
permalink: false
excerpt: false
categories: false
tags: true