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;//全局磨皮參數(shù)(平滑程度)
}
@property (nonatomic, assign) CGFloat intensity;
@end
/***********************************************/
//自定義的Shader著色器代碼
//Shader出現(xiàn)在OpenGL ES 2.0中踏施,允許創(chuàng)建自己的Shader炕倘。必須同時創(chuàng)建兩個Shader,分別是Vertex shader(頂點著色器)和Fragment shader(片段著色器).http://www.reibang.com/p/8687a040eb48
//Varyings:用來在Vertex shader和Fragment shader之間傳遞信息的躺坟,比如在Vertex shader中寫入varying值属桦,然后就可以在Fragment shader中讀取和處理
//Uniforms:在渲染循環(huán)里作為不變的輸入值
//vec2:兩個浮點數(shù)熊痴,適合在Fragment shader中保存X和Y坐標(biāo)的情況
//vec4:四個浮點數(shù),在圖像處理中持續(xù)追蹤每個像素的R,G,V,A這四個值聂宾。
//highp:屬性負(fù)責(zé)變量精度果善,這個被加入可以提高效率
//smpler2D:接收一個圖片的引用,當(dāng)做2D的紋理系谐。
//根據(jù)這個字符串創(chuàng)建Shader
NSString *const kGPUImageBeautifyFragmentShaderString = SHADER_STRING
(
varying highp vec2 textureCoordinate;//紋理坐標(biāo)1
varying highp vec2 textureCoordinate2;//紋理坐標(biāo)2
varying highp vec2 textureCoordinate3;//紋理坐標(biāo)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;
//判斷是不是邊緣,是不是皮膚.通過膚色檢測和邊緣檢測巾陕,只對皮膚和非邊緣部分進(jìn)行處理。
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)可以看成其中某一像素的坐標(biāo)梯刚。
- (id)init {
//Combination Filter根據(jù)kGPUImageBeautifyFragmentShaderString創(chuàng)建自定義的Shader.
//在自定義的Shader中對三個輸入進(jìn)行處理(雙邊模糊的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.調(diào)整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捕獲攝像頭圖像
調(diào)用newFrameReadyAtTime: atIndex:通知GPUImageBeautifyFilter;
2句喜、GPUImageBeautifyFilter調(diào)用newFrameReadyAtTime: atIndex:
通知GPUImageBilateralFliter輸入紋理已經(jīng)準(zhǔn)備好;
3沟于、GPUImageBilateralFliter 繪制圖像后在informTargetsAboutNewFrameAtTime()咳胃,
調(diào)用setInputFramebufferForTarget: atIndex:
把繪制的圖像設(shè)置為GPUImageCombinationFilter輸入紋理旷太,
并通知GPUImageCombinationFilter紋理已經(jīng)繪制完畢展懈;
4、GPUImageBeautifyFilter調(diào)用newFrameReadyAtTime: atIndex:
通知 GPUImageCannyEdgeDetectionFilter輸入紋理已經(jīng)準(zhǔn)備好供璧;
5存崖、同3,GPUImageCannyEdgeDetectionFilter 繪制圖像后睡毒,
把圖像設(shè)置為GPUImageCombinationFilter輸入紋理来惧;
6、GPUImageBeautifyFilter調(diào)用newFrameReadyAtTime: atIndex:
通知 GPUImageCombinationFilter輸入紋理已經(jīng)準(zhǔn)備好演顾;
7供搀、GPUImageCombinationFilter判斷是否有三個紋理,三個紋理都已經(jīng)準(zhǔn)備好后
調(diào)用GPUImageThreeInputFilter的繪制函數(shù)renderToTextureWithVertices: textureCoordinates:钠至,
圖像繪制完后葛虐,把圖像設(shè)置為GPUImageHSBFilter的輸入紋理,
通知GPUImageHSBFilter紋理已經(jīng)繪制完畢;
8棉钧、GPUImageHSBFilter調(diào)用renderToTextureWithVertices: textureCoordinates:繪制圖像屿脐,
完成后把圖像設(shè)置為GPUImageView的輸入紋理,并通知GPUImageView輸入紋理已經(jīng)繪制完畢宪卿;
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;//視頻相機(jī)對象
@property (strong, nonatomic) GPUImageView *filterView;//實時預(yù)覽的view,GPUImageView是響應(yīng)鏈的終點奢驯,一般用于顯示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.
//相機(jī)
self.videoCamera = [[GPUImageVideoCamera alloc] initWithSessionPreset:AVCaptureSessionPreset640x480 cameraPosition:AVCaptureDevicePositionFront];
self.videoCamera.outputImageOrientation = UIInterfaceOrientationPortrait;
self.videoCamera.horizontallyMirrorRearFacingCamera = YES;
//預(yù)覽層
self.filterView = [[GPUImageView alloc] initWithFrame:self.view.frame];
self.filterView.center = self.view.center;
[self.view addSubview:self.filterView];
//添加濾鏡到相機(jī)
[self.videoCamera addTarget:self.filterView];
[self.videoCamera startCameraCapture];
//設(shè)置按鈕
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:@"關(guān)閉" 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) {//如果已經(jīng)開啟了美顏,則
self.beautifyButton.selected = NO;
[self.videoCamera removeAllTargets];//移除原有的
[self.videoCamera addTarget:self.filterView];//添加普通預(yù)覽層
} else {//如果沒有開啟美顏
self.beautifyButton.selected = YES;
[self.videoCamera removeAllTargets];//移除原有的
GPUImageBeautifyFilter *beautifyFilter = [[GPUImageBeautifyFilter alloc] init];
[self.videoCamera addTarget:beautifyFilter];//添加美顏濾鏡層
[beautifyFilter addTarget:self.filterView];//美顏后再輸出到預(yù)覽層
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end