GPUImage–美顏濾鏡GPUImageBeautifyFilter

NO IMAGE

關於GPUimage的介紹請看這裡GPUImage:濾鏡、美顏、視訊流處理

美顏只是不同濾鏡組合起來的效果,實際上美顏也是一種濾鏡,它的需求較多,於是自稱一派。


GPUImageBeautifyFilter

/*
GPUImageBeautifyFilter是基於GPUImage的實時美顏濾鏡中的美顏濾鏡,包括GPUImageBilateralFilter、GPUImageCannyEdgeDetectionFilter、GPUImageCombinationFilter、GPUImageHSBFilter。
*/

在GPUImageBeautifyFilter.h中有:分別建立對應上面的物件

#import "GPUImage.h"
@class GPUImageCombinationFilter;
@interface GPUImageBeautifyFilter : GPUImageFilterGroup {
GPUImageBilateralFilter *bilateralFilter;
GPUImageCannyEdgeDetectionFilter *cannyEdgeFilter;
GPUImageCombinationFilter *combinationFilter;
GPUImageHSBFilter *hsbFilter;
}
@end

繪製流程分為:

  1. 準備紋理
  2. 繪製紋理
  3. 顯示處理後的紋理

一、 準備紋理:這裡用到的類
[GPUImageVideoCamera] –
[GPUImageBeautifyFilter] –
[GPUImageBilateralFliter] –
[GPUImageCombinationFilter] –
[GPUImageCannyEdgeDetectionFilter] –

準備 過程:

第一個紋理
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輸入紋理已經準備好;

原文:http://blog.sina.com.cn/s/blog_61bc01360102wpl2.html

二、繪製紋理:

7、判斷紋理數量
GPUImageCombinationFilter判斷是否有三個紋理,三個紋理都已經準備好後
呼叫GPUImageThreeInputFilter的繪製函式renderToTextureWithVertices: textureCoordinates:,
影象繪製完後,把影象設定為GPUImageHSBFilter的輸入紋理,
通知GPUImageHSBFilter紋理已經繪製完畢;
8、繪製紋理
GPUImageHSBFilter呼叫renderToTextureWithVertices:
textureCoordinates:繪製影象,
完成後把影象設定為GPUImageView的輸入紋理,並通知GPUImageView輸入紋理已經繪製完畢;

顯示紋理

9、GPUImageView把輸入紋理繪製到自己的幀快取,然後通過
[self.context presentRenderbuffer:GL_RENDERBUFFER];顯示到UIView上。

GPUImageBeautifyFilter.m檔案是這樣的

//
//  GPUImageBeautifyFilter.m
//  BeautifyFaceDemo
//
//  Created by guikz on 16/4/28.
//  Copyright © 2016年 guikz. All rights reserved.
//
#import "GPUImageBeautifyFilter.h"
// Internal CombinationFilter(It should not be used outside)
@interface GPUImageCombinationFilter : GPUImageThreeInputFilter
{
GLint smoothDegreeUniform;
}
@property (nonatomic, assign) CGFloat intensity;
@end
NSString *const kGPUImageBeautifyFragmentShaderString = SHADER_STRING
(
varying highp vec2 textureCoordinate;
varying highp vec2 textureCoordinate2;
varying highp vec2 textureCoordinate3;
uniform sampler2D inputImageTexture;
uniform sampler2D inputImageTexture2;
uniform sampler2D inputImageTexture3;
uniform mediump float smoothDegree;
void main()
{
highp vec4 bilateral = texture2D(inputImageTexture, textureCoordinate);
highp vec4 canny = texture2D(inputImageTexture2, textureCoordinate2);
highp vec4 origin = texture2D(inputImageTexture3,textureCoordinate3);
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
- (id)init {
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
- (id)init;
{
if (!(self = [super init]))
{
return nil;
}
// First pass: face smoothing filter
bilateralFilter = [[GPUImageBilateralFilter alloc] init];
bilateralFilter.distanceNormalizationFactor = 4.0;
[self addFilter:bilateralFilter];
// Second pass: edge detection
cannyEdgeFilter = [[GPUImageCannyEdgeDetectionFilter alloc] init];
[self addFilter:cannyEdgeFilter];
// Third pass: combination bilateral, edge detection and origin
combinationFilter = [[GPUImageCombinationFilter alloc] init];
[self addFilter:combinationFilter];
// Adjust HSB
hsbFilter = [[GPUImageHSBFilter alloc] init];
[hsbFilter adjustBrightness:1.1];
[hsbFilter adjustSaturation:1.1];
[bilateralFilter addTarget:combinationFilter];
[cannyEdgeFilter addTarget:combinationFilter];
[combinationFilter addTarget:hsbFilter];
self.initialFilters = [NSArray arrayWithObjects:bilateralFilter,cannyEdgeFilter,combinationFilter,nil];
self.terminalFilter = hsbFilter;
return self;
}
#pragma mark 繪製第一個紋理
- (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 == combinationFilter) {
textureIndex = 2;
}
[currentFilter setInputFramebuffer:newInputFramebuffer atIndex:textureIndex];
}
}
@end