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