GPUImage美颜实现

GPUImageBeautifyFilter.h文件中

#import <GPUImage/GPUImage.h>
@class GPUImageCombinationFilter;
@interface GPUImageBeautifyFilter : GPUImageFilterGroup //继承于图像滤镜组

{
    GPUImageBilateralFilter *bilateralFilter; //双边模糊(磨皮)滤镜--继承于高斯模糊滤镜GPUImageGaussianBlurFilter
    GPUImageCannyEdgeDetectionFilter *cannyEdgeFilter;//Canny边缘检测算法滤镜--继承于图像滤镜组GPUImageFilterGroup
    GPUImageHSBFilter *hsbFilter;//HSB颜色滤镜--继承于颜色矩阵滤镜GPUImageColorMatrixFilter
    GPUImageCombinationFilter *combinationFilter;//滤镜的组合---继承于三输入滤镜GPUImageThreeInputFilter
}

@end

GPUImageBeautifyFilter.m文件中

#import "GPUImageBeautifyFilter.h"
/***************************************************/
// Internal CombinationFilter(It should not be used outside)
@interface GPUImageCombinationFilter : GPUImageThreeInputFilter//继承于三输入的滤镜
{
    GLint smoothDegreeUniform;//全局磨皮参数(平滑程度)
}

@property (nonatomic, assign) CGFloat intensity;

@end


/***********************************************/
//自定义的Shader着色器代码
//Shader出现在OpenGL ES 2.0中,允许创建自己的Shader。必须同时创建两个Shader,分别是Vertex shader(顶点着色器)和Fragment shader(片段着色器).http://www.jianshu.com/p/8687a040eb48

//Varyings:用来在Vertex shader和Fragment shader之间传递信息的,比如在Vertex shader中写入varying值,然后就可以在Fragment shader中读取和处理
//Uniforms:在渲染循环里作为不变的输入值
//vec2:两个浮点数,适合在Fragment shader中保存X和Y坐标的情况
//vec4:四个浮点数,在图像处理中持续追踪每个像素的R,G,V,A这四个值。
//highp:属性负责变量精度,这个被加入可以提高效率
//smpler2D:接收一个图片的引用,当做2D的纹理。


//根据这个字符串创建Shader
NSString *const kGPUImageBeautifyFragmentShaderString = SHADER_STRING
(
 varying highp vec2 textureCoordinate;//纹理坐标1
 varying highp vec2 textureCoordinate2;//纹理坐标2
 varying highp vec2 textureCoordinate3;//纹理坐标3
 
 uniform sampler2D inputImageTexture;//输入图像纹理1
 uniform sampler2D inputImageTexture2;//输入图像纹理2
 uniform sampler2D inputImageTexture3;//输入图像纹理3
 
 uniform mediump float smoothDegree;//平滑度
 
 void main()
 {
     highp vec4 bilateral = texture2D(inputImageTexture, textureCoordinate);//双边模糊的2D纹理
     highp vec4 canny = texture2D(inputImageTexture2, textureCoordinate2);//边缘检测的2D纹理
     highp vec4 origin = texture2D(inputImageTexture3,textureCoordinate3);//原始图像的2D纹理
     highp vec4 smooth;
     lowp float r = origin.r;
     lowp float g = origin.g;
     lowp float b = origin.b;
     //判断是不是边缘,是不是皮肤.通过肤色检测和边缘检测,只对皮肤和非边缘部分进行处理。
     if (canny.r < 0.2 && r > 0.3725 && g > 0.1568 && b > 0.0784 && r > b && (max(max(r, g), b) - min(min(r, g), b)) > 0.0588 && abs(r-g) > 0.0588) {
         smooth = (1.0 - smoothDegree) * (origin - bilateral) + bilateral;
     }
     else {
         smooth = origin;
     }
     smooth.r = log(1.0 + 0.2 * smooth.r)/log(1.2);
     smooth.g = log(1.0 + 0.2 * smooth.g)/log(1.2);
     smooth.b = log(1.0 + 0.2 * smooth.b)/log(1.2);
     gl_FragColor = smooth;
 }
 );
/******************************************/


@implementation GPUImageCombinationFilter //组合滤镜
//Combination  Filter是我们自己定义的三输入的滤波器。三个输入分别是原图像A(x, y),双边滤波后的图像B(x, y),边缘图像C(x, y)。其中A,B,C可以看成是图像矩阵,(x,y)可以看成其中某一像素的坐标。

- (id)init {
    //Combination Filter根据kGPUImageBeautifyFragmentShaderString创建自定义的Shader.
    //在自定义的Shader中对三个输入进行处理(双边模糊的2D纹理,边缘检测的2D纹理,原始图像的2D纹理),见上面Shader代码
    if (self = [super initWithFragmentShaderFromString:kGPUImageBeautifyFragmentShaderString]) {
        smoothDegreeUniform = [filterProgram uniformIndex:@"smoothDegree"];
    }
    self.intensity = 0.5;
    return self;
}

- (void)setIntensity:(CGFloat)intensity {
    _intensity = intensity;
    [self setFloat:intensity forUniform:smoothDegreeUniform program:filterProgram];
}

@end


@implementation GPUImageBeautifyFilter//美颜滤镜
-(instancetype)init {
    if (!(self = [super init])) {
        return nil;
    }
    //1.双边模糊
    bilateralFilter = [[GPUImageBilateralFilter alloc] init];
    bilateralFilter.distanceNormalizationFactor = 4.0;
    [self addFilter:bilateralFilter];
    //2.边缘探测
    cannyEdgeFilter = [[GPUImageCannyEdgeDetectionFilter alloc] init];
    [self addFilter:cannyEdgeFilter];
    //3.合并
    combinationFilter = [[GPUImageCombinationFilter alloc] init];
    [self addFilter:combinationFilter];
    //4.调整HSB
    hsbFilter = [[GPUImageHSBFilter alloc] init];
    [hsbFilter adjustBrightness:1.1];//亮度
    [hsbFilter adjustSaturation:1.1];//饱和度
    
    //双边模糊完成后,输出到组合滤镜
    [bilateralFilter addTarget:combinationFilter];
    //边缘探测完成后,输出到组合滤镜
    [cannyEdgeFilter addTarget:combinationFilter];
    //组合滤镜处理完成后,输出到hsb滤镜
    [combinationFilter addTarget:hsbFilter];
    
    //初始滤镜组
    self.initialFilters = [NSArray arrayWithObjects:bilateralFilter,cannyEdgeFilter,combinationFilter, nil];
    //最终处理的滤镜
    self.terminalFilter = hsbFilter;
    return self;
}
#pragma mark GPUImageInput protocol

-(void)newFrameReadyAtTime:(CMTime)frameTime atIndex:(NSInteger)textureIndex {
    for (GPUImageOutput<GPUImageInput> *currentFilter in self.initialFilters) {
        if (currentFilter != self.inputFilterToIgnoreForUpdates) {
            if (currentFilter == combinationFilter) {
                textureIndex = 2;
            }
            [currentFilter newFrameReadyAtTime:frameTime atIndex:textureIndex];
        }
    }
}
-(void)setInputFramebuffer:(GPUImageFramebuffer *)newInputFramebuffer atIndex:(NSInteger)textureIndex {
    for (GPUImageOutput<GPUImageInput> *currentFilter in self.initialFilters) {
        if (currentFilter != self.inputFilterToIgnoreForUpdates) {
            if (currentFilter == combinationFilter) {
                textureIndex = 2;
            }
            [currentFilter setInputFramebuffer:newInputFramebuffer atIndex:textureIndex];
        }

    }
}
@end

/*
 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上。
*/

如何使用这个美颜工具类?
在自己的控制器中ViewController.m

#import "ViewController.h"
#import <GPUImage/GPUImage.h>
#import "GPUImageBeautifyFilter.h"
#import <Masonry/Masonry.h>

@interface ViewController ()
@property (strong, nonatomic) GPUImageVideoCamera *videoCamera;//视频相机对象
@property (strong, nonatomic) GPUImageView *filterView;//实时预览的view,GPUImageView是响应链的终点,一般用于显示GPUImage的图像。
@property (weak, nonatomic) UIButton *beautifyButton;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    //相机
    self.videoCamera = [[GPUImageVideoCamera alloc] initWithSessionPreset:AVCaptureSessionPreset640x480 cameraPosition:AVCaptureDevicePositionFront];
    self.videoCamera.outputImageOrientation = UIInterfaceOrientationPortrait;
    self.videoCamera.horizontallyMirrorRearFacingCamera = YES;
    
    //预览层
    self.filterView = [[GPUImageView alloc] initWithFrame:self.view.frame];
    self.filterView.center = self.view.center;
    [self.view addSubview:self.filterView];
    //添加滤镜到相机
    [self.videoCamera addTarget:self.filterView];
    [self.videoCamera startCameraCapture];
    //设置按钮
    UIButton *beautifyBtn = [UIButton buttonWithType:UIButtonTypeCustom];
    self.beautifyButton = beautifyBtn;
    [self.view addSubview:beautifyBtn];
    self.beautifyButton.backgroundColor = [UIColor whiteColor];
    [self.beautifyButton setTitle:@"开启" forState:UIControlStateNormal];
    [self.beautifyButton setTitle:@"关闭" forState:UIControlStateSelected];
    [self.beautifyButton setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
    [self.beautifyButton addTarget:self action:@selector(beautify) forControlEvents:UIControlEventTouchUpInside];
    beautifyBtn.frame = CGRectMake(100, 20, 100, 40);
}
- (void)beautify {
    if (self.beautifyButton.selected) {//如果已经开启了美颜,则
        self.beautifyButton.selected = NO;
        [self.videoCamera removeAllTargets];//移除原有的
        [self.videoCamera addTarget:self.filterView];//添加普通预览层
    } else {//如果没有开启美颜
        self.beautifyButton.selected = YES;
        [self.videoCamera removeAllTargets];//移除原有的
        GPUImageBeautifyFilter *beautifyFilter = [[GPUImageBeautifyFilter alloc] init];
        [self.videoCamera addTarget:beautifyFilter];//添加美颜滤镜层
        [beautifyFilter addTarget:self.filterView];//美颜后再输出到预览层
    }
}
- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end
GitHub:https://github.com/AlanZhangQ/GPUImage.git





  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值