简介
GPUImage是一个基于OpenGL(Open Graphics Library,开放图形库,是用于渲染2D、3D矢量图形的跨语言、跨平台的应用程序编程接口(API))进行图像处理的开源框架,内置大量滤镜,架构灵活,可以在其基础上很轻松地实现各种图像处理功能,对应的GPUImage for iOS和GPUImage for Android均有对应版本库支持。本文仅剖析iOS版本,安卓版本请自行学习。
那么下面,阅读理解又来了。。[Facepalm]
GPUImage uses OpenGL ES 2.0 shaders to perform image and video manipulation much faster than could be done in CPU-bound routines. However, it hides the complexity of interacting with the OpenGL ES API in a simplified Objective-C interface. This interface lets you define input sources for images and video, attach filters in a chain, and send the resulting processed image or video to the screen, to a UIImage, or to a movie on disk.
GPUImage使用OpenGL ES 2.0着色器去呈现图像和视频,这中操作比使用CPU处理渲染要快很多。 但是,它将OpenGL ES API的复杂交互隐藏在了简化的OC接口中。 此接口允许您定义图像和视频的输入源,增加滤镜(滤镜可以链式叠加,形成处理链),并将生成的处理过的图像或视频产出到屏幕,UIImage或磁盘上的电影文件。
Images or frames of video are uploaded from source objects, which are subclasses of GPUImageOutput. These include GPUImageVideoCamera (for live video from an iOS camera), GPUImageStillCamera (for taking photos with the camera), GPUImagePicture (for still images), and GPUImageMovie (for movies). Source objects upload still image frames to OpenGL ES as textures, then hand those textures off to the next objects in the processing chain.
图像或帧视频从源数据被上传,而这些数据都是GPUImageOutput的子类,其中包括了:GPUImageVideoCamera(适用于iOS相机的实时视频),GPUImageStillCamera(用于使用相机拍摄照片),GPUImagePicture(适用于静态图像)和GPUImageMovie(适用于电影)。源对象将静态图像帧作为纹理上传到OpenGL ES,然后将这些纹理移交给处理链中的下一个对象。
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.
处理链中的滤镜和其他后续元素遵循GPUImageInput协议,该协议允许它们从链中的前一个链接接收提供或处理的纹理并对其执行某些操作。处理链中某一步处理完成的对象可以作为目标,并且通过将多个目标添加到单个输出或滤镜可以对处理进行分支切分。
阅读完毕,仍旧有点懵逼。。。我们先来集成进项目看一下吧
添加 GPUImage 到自己的工程
然后。。直接添加pod又悲剧了。。这样是行不通的,然后接着阅读理解Adding the static library to your iOS project
然后看到了简单粗暴的【 it's fairly straightforward to add it to your application】直接拖,厉害厉害,佩服佩服,我们照做
1.简单粗暴拖进去
2.拖动GPUImage.xcodeproj到工程中
3.添加GPUImage作为Target Dependency
4.添加libGPUImage.a和frameworks
5.添加Header Search Paths【需要注意设置为recursive】
6.note
【1】如果你import出现错误: "Unknown class GPUImageView in Interface Builder" 或者你想用Interface Builder构建页面时,你还应该在build settings中的Other Linker Flags这一项添加-ObjC。
【2】GPUImage支持ARC,如果你想手动管理引用计数,那么你还需要在build settings中的Other Linker Flags这一项添加-fobjc-arc。
浅析GPUImage
首先我们先从目录来看一下大致结构如下:
然后按照readme动手先针对静态图片小试牛刀:
// 获取一张图片
UIImage *inputImage = [UIImage imageNamed:@"beijing"];
// 创建图片输入组件
GPUImagePicture *sourcePicture = [[GPUImagePicture alloc] initWithImage:inputImage smoothlyScaleOutput:YES];
// 创建褐色滤镜
GPUImageSepiaFilter *customFilter = [[GPUImageSepiaFilter alloc] init];
// 把滤镜串联在图片输入组件之后
[sourcePicture addTarget:customFilter];
// 创建ImageView输出组件
GPUImageView *imageView = [[GPUImageView alloc]initWithFrame:self.view.frame];
[self.view addSubview:imageView];
// 把ImageView输出组件串在滤镜链末尾
[customFilter addTarget:imageView];
// 调用图片输入组件的process方法,渲染结果就会绘制到imageView上
[sourcePicture processImage];
效果图如下:
轻松实现滤镜添加,手动完成美图秀秀简直easy~
其实查看文件发现,GPUImage为用户提供了炒鸡多的现有滤镜:
# pragma mark - 颜色处理
#import "GPUImageBrightnessFilter.h" //亮度,颜色范围从-1.0到1.0,0.0是正常亮度
#import "GPUImageLevelsFilter.h" //色阶,需注意相关参数设置范围为[0, 1]
#import "GPUImageExposureFilter.h" //曝光,曝光范围从-10.0到10.0,0.0是正常曝光
#import "GPUImageContrastFilter.h" //对比度,范围为0.0到4.0,1.0是正常值
#import "GPUImageSaturationFilter.h" //饱和度,范围为0.0到2.0,1.0是正常值
#import "GPUImageGammaFilter.h" //伽马线,范围为0.0到3.0,1.0是正常值
#import "GPUImageColorMatrixFilter.h" //4X4矩阵滤镜
#import "GPUImageRGBFilter.h" //RGB
#import "GPUImageHSBFilter.h" //HSB颜色滤镜--继承于矩阵滤镜
#import "GPUImageHueFilter.h" //色度
#import "GPUImageMonochromeFilter.h" //单色
#import "GPUImageFalseColorFilter.h" //色彩替换(替换亮部和暗部颜色)
#import "GPUImageHazeFilter.h" //朦胧加暗
#import "GPUImageSepiaFilter.h" //褐色(怀旧)
#import "GPUImageColorInvertFilter.h" //反色
#import "GPUImageGrayscaleFilter.h" //灰度
#import "GPUImageLuminanceThresholdFilter.h" //亮度阈
#import "GPUImageAdaptiveThresholdFilter.h" //自适应阈值
#import "GPUImageSolarizeFilter.h" //亮度高于阈值的像素将反转其颜色
#import "GPUImageAverageLuminanceThresholdFilter.h" //像素色值亮度平均,图像黑白(有类似漫画效果)
#import "GPUImageHistogramFilter.h" //色彩直方图,显示在图片上
#import "GPUImageHistogramGenerator.h" //特殊色彩直方图
#import "GPUImageHistogramEqualizationFilter.h" //直方图均衡化滤波器
#import "GPUImageToneCurveFilter.h" //色调曲线
#import "GPUImageHighlightShadowFilter.h" //提亮阴影
#import "GPUImageLookupFilter.h" //查找滤波器,调整色彩
#import "GPUImageAmatorkaFilter.h" //阿普特卡滤波器
#import "GPUImageMissEtikateFilter.h" //MissEtikate滤波器
#import "GPUImageSoftEleganceFilter.h" //基于查找的颜色重映射过滤器
#import "GPUImageOpacityFilter.h" //不透明度
#import "GPUImageAverageColor.h" //像素平均色值
#import "GPUImageLuminosity.h" //亮度平均
#import "GPUImageSolidColorGenerator.h" //纯色
#import "GPUImageChromaKeyFilter.h" //色度键
#import "GPUImageWhiteBalanceFilter.h" //白平横
#import "GPUImageLuminanceRangeFilter.h" //亮度范围滤镜
#pragma mark - 图像处理
#import "GPUImageTransformFilter.h" //形状变化
#import "GPUImageCropFilter.h" //剪裁
#import "GPUImageSharpenFilter.h" //锐化
#import "GPUImageUnsharpMaskFilter.h" //反遮罩锐化
#import "GPUImageBoxBlurFilter.h" //盒状模糊
#import "GPUImageGaussianBlurFilter.h" //高斯模糊
#import "GPUImageGaussianSelectiveBlurFilter.h" //高斯模糊,选择部分清晰
#import "GPUImageGaussianBlurPositionFilter.h" //高斯模糊,选择部分模糊
#import "GPUImageSingleComponentGaussianBlurFilter.h"//高斯模糊,仅在红色通道执行模糊
#import "GPUImageMedianFilter.h" //中间值,有种稍微模糊边缘的效果
#import "GPUImageBilateralFilter.h" //双边模糊
#import "GPUImageTiltShiftFilter.h" //条纹模糊,中间清晰,上下两端模糊
#import "GPUImage3x3ConvolutionFilter.h" //3x3卷积,高亮大色块变黑,加亮边缘、线条等
#import "GPUImageLaplacianFilter.h"
#import "GPUImageSobelEdgeDetectionFilter.h" //Sobel边缘检测算法(白边,黑内容,有点漫画的反色效果)
#import "GPUImageThresholdEdgeDetectionFilter.h" //阈值边缘检测(效果与上差别不大)
#import "GPUImageDirectionalSobelEdgeDetectionFilter.h"//彩色浮雕
#import "GPUImageDirectionalNonMaximumSuppressionFilter.h"//黑色反差
#import "GPUImageWeakPixelInclusionFilter.h" //像素选择
#import "GPUImageNonMaximumSuppressionFilter.h" //非最大抑制,只显示亮度最高的像素,其他为黑
#import "GPUImageThresholdedNonMaximumSuppressionFilter.h" //与上相比,像素丢失更多
#import "GPUImageCannyEdgeDetectionFilter.h" //Canny边缘检测算法(比上更强烈的黑白对比度)
#import "GPUImagePrewittEdgeDetectionFilter.h" //普瑞维特(Prewitt)边缘检测(效果与Sobel差不多,貌似更平滑)
#import "GPUImageXYDerivativeFilter.h" //XYDerivative边缘检测,画面以蓝色
#import "GPUImageHarrisCornerDetectionFilter.h" //Harris角点检测,会有绿色小十字显示
#import "GPUImageNobleCornerDetectionFilter.h" //Noble角点检测,检测点更多
#import "GPUImageShiTomasiFeatureDetectionFilter.h" //ShiTomasi角点检测,与上差别不大
#import "GPUImageFASTCornerDetectionFilter.h" //(FAST)特征检测器
#import "GPUImageCrosshairGenerator.h" //十字
#import "GPUImageDilationFilter.h" //扩展边缘模糊,变黑白
#import "GPUImageRGBDilationFilter.h" //RGB扩展边缘模糊,有色彩
#import "GPUImageErosionFilter.h" //侵蚀边缘模糊,变黑白
#import "GPUImageRGBErosionFilter.h" //RGB侵蚀边缘模糊,有色彩
#import "GPUImageOpeningFilter.h" //黑白色调模糊
#import "GPUImageRGBOpeningFilter.h" //彩色模糊
#import "GPUImageClosingFilter.h" //黑白色调模糊,暗色会被提亮
#import "GPUImageRGBClosingFilter.h" //彩色模糊,暗色会被提亮
#import "GPUImageColorPackingFilter.h" //色彩丢失,模糊(类似监控摄像效果)
#import "GPUImageLocalBinaryPatternFilter.h" //图像黑白化,并有大量噪点
#import "GPUImageColorLocalBinaryPatternFilter.h" //图像黑白化但有部分彩色,并有大量噪点
#import "GPUImageLanczosResamplingFilter.h" //Lanczos重取样,模糊效果
#import "GPUImageLowPassFilter.h" //用于图像加亮
#import "GPUImageHighPassFilter.h" //图像低于某值时显示为黑
#import "GPUImageMotionDetector.h" //动作检测
#import "GPUImageHoughTransformLineDetector.h" //线条检测
#import "GPUImageParallelCoordinateLineTransformFilter.h" //平行线检测
#import "GPUImageLineGenerator.h" //线条
#import "GPUImageMotionBlurFilter.h" //动态模糊
#import "GPUImageZoomBlurFilter.h" //放大模糊
#import "GPUImageiOSBlurFilter.h" //亮度范围模糊
#pragma mark - 混合处理
#import "GPUImageSourceOverBlendFilter.h" //源混合
#import "GPUImageColorBurnBlendFilter.h" //色彩加深混合
#import "GPUImageColorDodgeBlendFilter.h" //色彩减淡混合
#import "GPUImageDarkenBlendFilter.h" //加深混合,通常用于重叠类型
#import "GPUImageLightenBlendFilter.h" //减淡混合,通常用于重叠类型
#import "GPUImageDifferenceBlendFilter.h" //差异混合,通常用于创建更多变动的颜色
#import "GPUImageDissolveBlendFilter.h" //溶解
#import "GPUImageExclusionBlendFilter.h" //排除混合
#import "GPUImageHardLightBlendFilter.h" //强光混合,通常用于创建阴影效果
#import "GPUImageSoftLightBlendFilter.h" //柔光混合
#import "GPUImageAddBlendFilter.h" //通常用于创建两个图像之间的动画变亮模糊效果
#import "GPUImageSubtractBlendFilter.h" //差值混合,通常用于创建两个图像之间的动画变暗模糊效果
#import "GPUImageDivideBlendFilter.h" //通常用于创建两个图像之间的动画变暗模糊效果
#import "GPUImageMultiplyBlendFilter.h" //通常用于创建阴影和深度效果
#import "GPUImageOverlayBlendFilter.h" //叠加,通常用于创建阴影效果
#import "GPUImageScreenBlendFilter.h" //屏幕包裹,通常用于创建亮点和镜头眩光
#import "GPUImageChromaKeyBlendFilter.h" //色度键混合
#import "GPUImageAlphaBlendFilter.h" //透明混合,通常用于在背景上应用前景的透明度
#import "GPUImageNormalBlendFilter.h" //两个图像的正常混合
#import "GPUImageColorBlendFilter.h" //两个图像的颜色混合
#import "GPUImageHueBlendFilter.h" //两个图像的色调混合
#import "GPUImageSaturationBlendFilter.h" //两个图像的饱和度混合
#import "GPUImageLuminosityBlendFilter.h" //两个图像的亮度混合
#import "GPUImageLinearBurnBlendFilter.h" //两个图像的线性刻录混合
#import "GPUImagePoissonBlendFilter.h" //两个图像的泊松混合
#import "GPUImageMaskFilter.h" //遮罩混合
#pragma mark - 视觉效果
#import "GPUImagePerlinNoiseFilter.h" //柏林噪点,花边噪点
#import "GPUImagePixellateFilter.h" //像素化
#import "GPUImagePixellatePositionFilter.h" //像素化位置
#import "GPUImagePolkaDotFilter.h" //像素圆点花样
#import "GPUImageHalftoneFilter.h" //点染,图像黑白化,由黑点构成原图的大致图形
#import "GPUImagePolarPixellateFilter.h" //同心圆像素化
#import "GPUImageCrosshatchFilter.h" //交叉线阴影,形成黑白网状画面
#import "GPUImageSketchFilter.h" //素描
#import "GPUImageThresholdSketchFilter.h" //阀值素描,形成有噪点的素描
#import "GPUImageEmbossFilter.h" //浮雕效果,带有点3d的感觉
#import "GPUImageToonFilter.h" //卡通效果(黑色粗线描边)
#import "GPUImageSmoothToonFilter.h" //相比上面的效果更细腻,上面是粗旷的画风
#import "GPUImageCGAColorspaceFilter.h" //CGA色彩滤镜,形成黑、浅蓝、紫色块的画面
#import "GPUImagePosterizeFilter.h" //色调分离,形成噪点效果
#import "GPUImageSwirlFilter.h" //漩涡,中间形成卷曲的画面
#import "GPUImageBulgeDistortionFilter.h" //凸起失真,鱼眼效果
#import "GPUImagePinchDistortionFilter.h" //收缩失真,凹面镜
#import "GPUImageStretchDistortionFilter.h" //伸展失真,哈哈镜
#import "GPUImageSphereRefractionFilter.h" //球形折射,图形倒立
#import "GPUImageGlassSphereFilter.h" //水晶球效果
#import "GPUImageKuwaharaFilter.h" //桑原(Kuwahara)滤波,水粉画的模糊效果;处理时间比较长,慎用
#import "GPUImageKuwaharaRadius3Filter.h" //修改版本的Kuwahara过滤器,经过优化,可以工作在三像素半径
#import "GPUImageVignetteFilter.h" //晕影,形成黑色圆形边缘,突出中间图像的效果
#import "GPUImageJFAVoronoiFilter.h" //生成Voronoi映射,用于后期阶段
#import "GPUImageMosaicFilter.h" //黑白马赛克
#import "GPUImageVoronoiConsumerFilter.h" //进行Voronoi映射,并使用它来过滤传入的映像
查看继承关系,我们可以看到数据源的多个类继承自GPUImageOutput,滤镜基本上都继承自GPUImageFilter,而GPUImageFilter继承自GPUImageOutput,输出组件均遵循GPUImageInput协议。下面我们分别来解析一下这几种类别。
1.GPUImageFilter解析
1.根据设置的标注模式设置获取输入纹理的坐标
+ (const GLfloat *)textureCoordinatesForRotation:(GPUImageRotationMode)rotationMode;
2.赋予纹理新的顶点和坐标,输出绘制结果
// 获取绘制GPUImageFramebuffer
outputFramebuffer = [[GPUImageContext sharedFramebufferCache] fetchFramebufferForSize:[self sizeOfFBO] textureOptions:self.outputTextureOptions onlyTexture:NO];
// 调整视口大小
[outputFramebuffer activateFramebuffer];
// usingNextFrameForImageCapture代表着输出的结果会被用于获取图像,所以在绘制之前要加锁
if (usingNextFrameForImageCapture)
{
[outputFramebuffer lock];
}
// 设置当前响应链对象为最新
[self setUniformsForProgramAtIndex:0];
// 清除画布
glClearColor(backgroundColorRed, backgroundColorGreen, backgroundColorBlue, backgroundColorAlpha);
glClear(GL_COLOR_BUFFER_BIT);
// 绑定输入纹理,这样OpenGL ES才能确定要处理纹理数据
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, [firstInputFramebuffer texture]);
glUniform1i(filterInputTextureUniform, 2);
// 绑定顶点和纹理坐标
glVertexAttribPointer(filterPositionAttribute, 2, GL_FLOAT, 0, 0, vertices);
glVertexAttribPointer(filterTextureCoordinateAttribute, 2, GL_FLOAT, 0, 0, textureCoordinates);
// 绘制图元
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
// 输入纹理使用完毕,解锁
[firstInputFramebuffer unlock];
// 如果设置了usingNextFrameForImageCapture,则会通过GCD信号量来通知仍在等待绘制完成的函数
if (usingNextFrameForImageCapture)
{
dispatch_semaphore_signal(imageCaptureSemaphore);
}
- (void)activateFramebuffer;
{
// 绑定自己的帧缓存
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
// 调整视口大小
glViewport(0, 0, (int)_size.width, (int)_size.height);
}
3.当本次帧绘制完成后,通知targets,并将本次的输出设置为targets的输入纹理
- (void)informTargetsAboutNewFrameAtTime:(CMTime)frameTime;
{
if (self.frameProcessingCompletionBlock != NULL)
{
self.frameProcessingCompletionBlock(self, frameTime);
}
// Get all targets the framebuffer so they can grab a lock on it
// 遍历所有链上的target
for (id<GPUImageInput> currentTarget in targets)
{
if (currentTarget != self.targetToIgnoreForUpdates)
{
NSInteger indexOfObject = [targets indexOfObject:currentTarget];
NSInteger textureIndex = [[targetTextureIndices objectAtIndex:indexOfObject] integerValue];
// 当self的帧绘制完成后,通知自己的targets,并将自己的输出设置为targets的输入纹理
[self setInputFramebufferForTarget:currentTarget atIndex:textureIndex];
[currentTarget setInputSize:[self outputFrameSize] atIndex:textureIndex];
}
}
// Release our hold so it can return to the cache immediately upon processing
// 然后解锁自己使用的输出缓冲区,(在上一个函数已经lock了这个缓冲区,所以这里的unlock不会马上回收内存,等到targets使用完自己的纹理后调用unlock,缓存会被回收)
[[self framebufferForOutput] unlock];
if (usingNextFrameForImageCapture)
{
// usingNextFrameForImageCapture = NO;
}
else
{
[self removeOutputFramebuffer];
}
// Trigger processing last, so that our unlock comes first in serial execution, avoiding the need for a callback
for (id<GPUImageInput> currentTarget in targets)
{
if (currentTarget != self.targetToIgnoreForUpdates)
{
NSInteger indexOfObject = [targets indexOfObject:currentTarget];
NSInteger textureIndex = [[targetTextureIndices objectAtIndex:indexOfObject] integerValue];
// 在设置完缓冲区后,self会通知所有targets(除了设置忽略的)
[currentTarget newFrameReadyAtTime:frameTime atIndex:textureIndex];
}
}
}
2.GPUImageOutput
作为的父类,提供了添加和移除target链的对应函数
- (NSArray*)targets;
- (void)addTarget:(id<GPUImageInput>)newTarget;
- (void)addTarget:(id<GPUImageInput>)newTarget atTextureLocation:(NSInteger)textureLocation;
- (void)removeTarget:(id<GPUImageInput>)targetToRemove;
- (void)removeAllTargets;
3.GPUImageInput协议
// 所有渲染的入口方法
- (void)newFrameReadyAtTime:(CMTime)frameTime atIndex:(NSInteger)textureIndex;
// 设置响应链的下一个对象帧绘制完成,并将自己的输出设置为targets的输入纹理
- (void)setInputFramebuffer:(GPUImageFramebuffer *)newInputFramebuffer atIndex:(NSInteger)textureIndex;
// 下一个可用的纹理坐标
- (NSInteger)nextAvailableTextureIndex;
// 设置对象大小
- (void)setInputSize:(CGSize)newSize atIndex:(NSInteger)textureIndex;
// 设置翻转模式
- (void)setInputRotation:(GPUImageRotationMode)newInputRotation atIndex:(NSInteger)textureIndex;
// 获取最大输出对象大小
- (CGSize)maximumOutputSize;
// 终止渲染
- (void)endProcessing;
// 这个target对象是否应该在渲染链中被忽略
- (BOOL)shouldIgnoreUpdatesToThisTarget;
- (BOOL)enabled;
// 是否需要单色输入
- (BOOL)wantsMonochromeInput;
// 设置当前接手单色输入
- (void)setCurrentlyReceivingMonochromeInput:(BOOL)newValue;
4.GPUImageFramebuffer
GPUImageFramebuffer类是被用来管理纹理缓存格式、帧缓存的buffer。
整体流程
1.输入
GPUImage提供了多种不同的输入组件【GPUImageVideoCamera(适用于iOS相机的实时视频),GPUImageStillCamera(用于使用相机拍摄照片),GPUImagePicture(适用于静态图像)和GPUImageMovie(适用于电影)】,但是无论是哪种输入源,获取数据的本质都是把图像数据转换成OpenGL纹理。
2.处理
GPUImage的图像处理过程,是以输入组件、效果滤镜、输出组件串联在一起的处理链的形式组成的,每次addTarget就是一次处理链的叠加,渲染时输入数据会按顺序进行传递-处理-最终输出。就像我们上面章节中举得实际例子,也是通过叠加Target实现处理流转。
3.输出
1.GPUImageView主要用来加载图像
2.GPUImageMovieWriter主要用于将视频输出到磁盘
3.GPUImageTextureOutput和GPUImageRawDataOutput是纹理和数据输出
小结
其实GPUImage的原理是使用GPUImageFilter来接收源图像,通过自定义的顶点、片元着色器来渲染新的图像,并在绘制完成后通知响应链的下一个对象,将本次绘制完成的输出源作为下一个处理处理对象的输入源,直至响应链对象全部处理完毕,输出最终的输出结果。