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





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章