美文网首页音频开发中有帮助的iOS文章iOS
GPUImage详细解析(三)- 实时美颜滤镜

GPUImage详细解析(三)- 实时美颜滤镜

作者: 落影loyinglin | 来源:发表于2016-05-19 15:44 被阅读12417次

回顾

解析(一)
解析(二)

  • GPUImageFilter就是用来接收源图像,通过自定义的顶点、片元着色器来渲染新的图像,并在绘制完成后通知响应链的下一个对象。
  • GPUImageFramebuffer就是用来管理纹理缓存的格式与读写帧缓存的buffer。
  • GPUImageVideoCameraGPUImageOutput的子类,提供来自摄像头的图像数据作为源数据,一般是响应链的源头。
  • GPUImageView是响应链的终点,一般用于显示GPUImage的图像。

琨君基于GPUImage的实时美颜滤镜对GPUImage实现美颜滤镜的原理和思路做了详细介绍。
本文以琨君的代码为demo,结合前两篇解析,探究美颜过程中的GPUImage实现。

GPUImage类介绍

1、GPUImageFilterGroup

GPUImageFilterGroup是多个filter的集合,terminalFilter为最终的filter,initialFilters为filter数组。GPUImageFilterGroup本身不绘制图像,对GPUImageFilterGroup添加删除Target操作的操作都会转为terminalFilter的操作。

2、GPUImageTwoInputFilter

GPUImageTwoInputFilterGPUImageFilter的子类,对两个输入纹理进行通用的处理,需要继承它并准备自己的片元着色器。
两个输入纹理默认为inputImageTextureinputImageTexture2

  • 重写了下面的函数,修改GPUImageFilter绘制的逻辑。
- (void)renderToTextureWithVertices:(const GLfloat *)vertices
 textureCoordinates:(const GLfloat *)textureCoordinates;

下面这部分是核心的绘制逻辑:
glActiveTexture()是选择纹理单元,glBindTexture()是把纹理单元和firstInputFramebuffersecondInputFramebuffer管理的纹理内存绑定。glUniform1i()告诉GLSL选择的纹理单元是2。
这部分在上一篇介绍也有提到,再详细阐述:glActiveTexture()选择的是纹理单元,和glGenTextures()返回的数字没有关系,可以在纹理单元2上面绑定纹理12。
glGenTextures()返回的纹理可以是GL_TEXTURE_2D类型也可以是GL_TEXTURE_CUBE_MAP类型,取决于glBindTexture()第一次绑定纹理的是GL_TEXTURE_2D还是GL_TEXTURE_CUBE_MAP

    glActiveTexture(GL_TEXTURE2);
    glBindTexture(GL_TEXTURE_2D, [firstInputFramebuffer texture]);
    glUniform1i(filterInputTextureUniform, 2);    

    glActiveTexture(GL_TEXTURE3);
    glBindTexture(GL_TEXTURE_2D, [secondInputFramebuffer texture]);
    glUniform1i(filterInputTextureUniform2, 3);
  • nextAvailableTextureIndex用于获取下一个纹理索引
- (NSInteger)nextAvailableTextureIndex;
{
    if (hasSetFirstTexture)
    {
        return 1;
    }
    else
    {
        return 0;
    }
}

setInputFramebuffer: atIndex:会根据上面获取的textureIndex设置firstInputFramebuffersecondInputFramebuffer。如果是textureIndex = 0,设置hasSetFirstTexture表示已经设置第一个纹理。

3、GPUImageThreeInputFilter

GPUImageThreeInputFilter的逻辑与GPUImageTwoInputFilter类似,增加了thirdInputFramebuffer作为第三个纹理inputImageTexture3的输入。

4、GPUImageBeautifyFilter

GPUImageBeautifyFilter基于GPUImage的实时美颜滤镜中的美颜滤镜,包括GPUImageBilateralFilterGPUImageCannyEdgeDetectionFilterGPUImageCombinationFilterGPUImageHSBFilter

绘制流程

绘制流程图
  • 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上。

总结

GPUImageFilter
GPUImageFramebuffer
GPUImageVideoCamera
GPUImageView
GPUImageFilterGroup
GPUImageTwoInputFilter
GPUImageThreeInputFilter
这是学习这个demo需要了解的7个类。
在绘制流程图的过程中,对GPUImage的响应链有了更清晰的认识。

相关文章

  • GPUImage详细解析(三)- 实时美颜滤镜

    回顾 解析(一)解析(二) GPUImageFilter就是用来接收源图像,通过自定义的顶点、片元着色器来渲染新的...

  • iOS GPUImage实时美颜滤镜

    转载自:实战分享:实时美颜滤镜是怎样炼成的 1.背景 前段时间由于项目需求,做了一个基于GPUImage的实时美颜...

  • iOS GPUImage实时美颜滤镜

    1.背景 前段时间由于项目需求,做了一个基于GPUImage的美颜+滤镜相机。现在各种各样的直播、小视频App层出...

  • GPUImage-实时美颜滤镜

    GPUImage类介绍 GPUImageFilter就是用来接收源图像,通过自定义的顶点、片元着色器来渲染新的图像...

  • iOS-DIY美颜相机

    本例是使用GPUImage开源框架,生成美颜相机。实时采集画面,进行美颜。 GPUImage GPUImage是开...

  • iOS -- Xcode导入GPUImage

    GPUImage GPUImage 是基于GPU做图片滤镜,摄像头实时滤镜的第三方库,该库中内置了125种滤镜效果...

  • 基于GPUImage的实时美颜滤镜

    1.背景 前段时间由于项目需求,做了一个基于GPUImage的实时美颜滤镜。现在各种各样的直播、视频App层出不...

  • 基于GPUImage的实时美颜滤镜

    1.背景 前段时间由于项目需求,做了一个基于GPUImage的实时美颜滤镜。现在各种各样的直播、视频App层出不穷...

  • 基于GPUImage的实时美颜滤镜

    飞机票:http://www.jianshu.com/p/945fc806a9b4

  • 将GPUImage添加到工程里

    将GPUImage添加到工程里 GPUImage提供图像处理滤镜,并且支持照相机和摄像机的实时滤镜GPUImage...

网友评论

  • 当地比较英俊的男子:您好,GPUImageStillCamera 实时视频流下如何获取每一帧,发现这个- (void)willOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer不起作用,可以帮忙一下吗?
    有没有时间:@当地比较英俊的男子 添加GPUImageView作为渲染既可解决
  • 新其谦:楼主还在吗???
    新其谦:@新其谦 GPU还有其他的作用嘛?在人脸识别方面
    新其谦:@新其谦 我想咨询一个小问题,通过GPU
    如果优化人脸识别,查看了很多资料,主要就是一个意思,计算速度变快了
    落影loyinglin:@新其谦 在的,老铁。请问什么事情
  • littleDad:为什么 感觉 demo和 博客不是在一条线上,讲的 api 里面都没使用上
  • Zszen:你好, 大师, 请问如何避免GPUImageAverageColor和rotateCamera冲突, 我用avg color做了个自动光线感应的效果, 但是发现这个插件和摄像头切换存在严重冲突问题, 只要有这个滤镜或其衍生滤镜average brightness在就会导致rotateCamera很高几率崩溃, 大概在0~3次内必崩, 暂无解决办法
  • Zszen:- (void)newFrameReadyAtTime:(CMTime)frameTime atIndex:(NSInteger)textureIndex

    - (void)setInputFramebuffer:(GPUImageFramebuffer *)newInputFramebuffer atIndex:(NSInteger)textureIndex没必要重写
    super处理以后加一句
    [combinationFilter newFrameReadyAtTime:frameTime atIndex:2];即可
  • 899e2d74bdeb:请问,我想获取添加滤镜后的数据用来进行推流,设置响应链为GPUImageVideoCamera->GPUImageSepiaFilter->GPUImageView ,然后通过GPUImageSepiaFilter的setFrameProcessingCompletionBlock方法获取视频数据,但是获取到的视频数据却是没有添加滤镜时的视频时的数据。请问用什么方法获取添加滤镜后的视频数据。
  • ShannonChenCHN:@protocol YuvPreProcessorProtocol <NSObject>

    // modify this frame in this callback
    @required
    - (void)onFrameAvailable:(unsigned char *)y ubuf:(unsigned char *)u vbuf:(unsigned char *)v ystride:(int)ystride ustride:(int)ustride vstride:(int)vstride width:(int)width height:(int)height;

    @EnD

    @interface YuvPreProcessor : NSObject

    @property (nonatomic, weak) id<YuvPreProcessorProtocol> delegate;

    // enable preprocessor
    - (void)turnOn;
    // disable preprocessor
    - (void)turnOff;

    @EnD

    我用的是第三方的 SDK,他们给了这样一个处理图像的接口,我应该怎么做才能借助 GPUImage 来给这个接口添加美颜功能呢?
    落影loyinglin:@祥龙Shannon GPU里面就有YUV抓RGB的矩阵。
    ShannonChenCHN:@落影loyinglin 十分感谢您的解答,我现在的疑问是 GPUImage 的 output 怎么转成他这里的 YUV 格式呢?我应该看些什么资料?从哪里入手?
    落影loyinglin:@祥龙Shannon 如果协议不要实时返回,你可以用GPUImageDataInput/Output来处理图像输入输出。
  • o0阿拉斯加的狗0o:@落影loyinglin 您好,为什么要使用GPUImageHSBFilter呢?不使用可不可以啊?谢谢了
    落影loyinglin:@o0一路向北0o 美颜算法来自昆君。
  • 0a7ea1459b80:你好,请问一下,使用GPUImageVideoCamera作为输入源,实时效果通过GPUImageView显示出来的,那么滤镜处理的数据在哪里那呢(上传),是通过GPUImageVideoCamera的代理方法- (void)willOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer,这个进行转换的吗

    o0阿拉斯加的狗0o:@落影loyinglin 您好,为什么要使用GPUImageHSBFilter呢?不使用可不可以啊?谢谢了
    落影loyinglin:@哈嘿吼 你可以添加一个新的data类,接受输出的数据。
    0a7ea1459b80:@哈嘿吼 是通过GPUImageMovieWriter来获取,还是通过GPUImageRawDataOutput来呢
  • 9d461a3948ed:请问我用lookup的那三个图片做成的滤镜给静态图片添加滤镜为什么没有效果呢,添加其他滤镜却有效果
  • 乐视薯片:我想问一下,GPUImageBeautifyFilter 里 有这样两句
    [bilateralFilter addTarget:combinationFilter];
    [cannyEdgeFilter addTarget:combinationFilter];
    这又是什么意思啊
  • 自由马_runner:我不能用AVAssetWritter写GPUImageRawDataOutput回调的数据,在appendSampleBuffer时总是失败。代码:https://github.com/fenglinxiu/GPUImageDemo.git 请大神指点
    自由马_runner:这个问题已经困扰我很多天了。希望指教。
  • 84c60e43d0e4:如果我想修改GPUImageBilateralFliter的distanceNormalizationFactor参数,要怎么修改呢,我试着修改一直都没有生效。 单独使用GPUImageBilateralFliter滤镜时修改是有效的。
    落影loyinglin:@豹豹崔 先确定combinationfilter的两个输入是否异常,再看看结合是否存在问题,最后检查hsbfilter的输入输出。
    落影loyinglin:@豹豹崔 这几天比较忙。假设你修改是有效的,那么看看输出的output。把屏幕切成几份,把所有的filter的oupout都显示一份到屏幕上。
    84c60e43d0e4:@豹豹崔 是我描述的不清楚吗。。。。
  • 我的大名叫小爱:你好.我在使用开源库LFlivekit 中使用 GPUimage 直播推流添加滤镜的这部分代码 .... (LFVideoCapture.m文件中)
    [_emptyFilter removeAllTargets];
    [_filter removeAllTargets];
    [_videoCamera removeAllTargets];
    [_beau removeAllTargets];

    _filter = [[GPUImageUnsharpMaskFilter alloc] init];
    _beau = [[LFGPUImageBeautyFilter alloc] init];
    _emptyFilter = [[GPUImageColorInvertFilter alloc]init];

    [_videoCamera addTarget:_filter];
    [_filter addTarget:_beau];
    [_beau addTarget:_emptyFilter];
    [_emptyFilter addTarget:_gpuImageView];//_gpuImageView为一个 GPUImageView 用于显示

    __weak typeof(self) _self = self;
    [_emptyFilter setFrameProcessingCompletionBlock:^(GPUImageOutput *output, CMTime time) {
    [_self processVideo:output];
    }];

    上面是简化后的代码.如果想要定制滤镜实现实时滤镜...在电脑上使用 VLC 播放器播放的时候正常播放 但是如果代码换成

    [_testfilter removeAllTargets];
    [_videoCamera removeAllTargets];
    _testfilter = [[GPUImageColorInvertFilter alloc]init];
    __weak typeof(self) _self = self;
    [_filter forceProcessingAtSize:_configuration.videoSize];
    [_testfilter setFrameProcessingCompletionBlock:^(GPUImageOutput *output, CMTime time) {
    [_self processVideo:output];
    }];
    [_videoCamera addTarget:_testfilter];
    [_testfilter addTarget:_gpuImageView];

    如果用下面的代码...播放能播放.滤镜好像也加上了 .但是会闪屏. 好像不是每一帧的数据都加上了滤镜效果,请问这可能是什么原因???
    我的大名叫小爱:@落影lying-in 好的 给个邮箱地址 我整理好了发给你.
    落影loyinglin:@我的大名叫小爱 有遇到过这个问题。后来解决了。你可以整理个demo,我看看
    落影loyinglin:@我的大名叫小爱 加不上滤镜可能是处理不过来。你有demo吗
  • 兔矢志:您好,我问一下,/// @abstract 获取到摄像头原数据时的回调, 便于开发者做滤镜等处理
    - (CVPixelBufferRef)cameraStreamingSession:(PLCameraStreamingSession *)session cameraSourceDidGetPixelBuffer:(CVPixelBufferRef)pixelBuffer; 这个CVPixelBufferRef 类型的数据要怎么操作加滤镜呢,我用coreImage 可以做,但是我想用GPUImage 然后就傻了,做不好了
    落影loyinglin:@兔矢志 核心是如何把CVPixelBufferRef加入到GPUImage 的响应链。可以通过CVPixelBufferRef>CGImageRef>GPUImagePicture,加入响应链。CVPixelBufferRef 和 CGImageRef 互转的网上很多资料。
    兔矢志:@落影lying-in 因为我是做直播,在没有用到这个接口的时候是已经可以直播了。所以我感觉如果再用 GPUImageVideoCamera 获取摄像头数据,用GPUImageView做滤镜的话。会出现我手机上显示,但是推流却不行。 我想有没有什么方法 直接对 pixelBuffer 数据进行操作, 比如CVPixelBufferRef -> (滤镜处理之后)CVPixelBufferRef 或者是CVPixelBufferRef -> (滤镜处理之后)CGImageRef-> CVPixelBufferRef 这样的,大神可以给出思路吗。不懂怎么操作这个数据
    落影loyinglin:@兔矢志 你可以使用GPUImageCamera直接录制视频,再添加GPUImage的滤镜。
  • 1cd0b31b8ec4:你好 谢谢你的分享 因为录制的时候 只有12fps 所以想要删除GPUImageCannyEdgeDetectionFilter 具体应该怎么修改呢 求助
    1cd0b31b8ec4:你好 谢谢你百忙之中抽出时间回答我的问题 我做过测试如果是用GPUimage 自己的内置滤镜录制帧率都能达到29.9fps 就是用这个demo 加上滤镜就只有12fps 注: 我用的是GPUImageMovieWriter 来录制的
    落影loyinglin:@1cd0b31b8ec4 看了下 帧率低先查一下 其它原因 ,gpu一般都不是性能瓶颈。要删掉也容易 直接把上面的输出指向下一个即可
    落影loyinglin:@1cd0b31b8ec4 刚刚看到,你说的是这个demo的吗?

本文标题:GPUImage详细解析(三)- 实时美颜滤镜

本文链接:https://www.haomeiwen.com/subject/lffgrttx.html