CoreImage图片滤镜效果详解

在iOS中,如果需要使用滤镜功能,可以使用自带提供的Core Image框架。它为我们提供了很多可用高效的滤镜选择,在Core Image框架中,需要了解CIImage,CIFilter,CIContext这三大类,其中CIImage代表需要处理的图片蓝本,CIFilter代表要使用的滤镜(对CIImage是使用滤镜链表的形式,只有当使用CIContext才真正渲染,对其使用CIFilter是不会马上渲染的,滤镜有叠加使用的功效),CIContext是进行滤镜渲染的上下文(它有分为cpu渲染和gpu渲染两种方式,其中cpu渲染是可以在后台进行渲染,但是速度没有这么高效,对于非实时的渲染,例如图片,可以使用cpu。gpu的渲染不能在后台进行,但是效率快,对于实时性的渲染可以使用gpu,例如视频的每一帧的渲染)。其中,CIImage和CIContext是线程安全的,CIFilter则是线程不安全,不能被多个线程共享。


    imageV = [[UIImageView alloc]initWithFrame:CGRectMake(70, 100, 200, 250)];
    imageV.image = [UIImage imageNamed:@"test.png"];
    [self.view addSubview:imageV];
    dispatch_queue_t globel = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    //因为滤镜的渲染是需要耗时的,所以不把它放到主线程中进行
    dispatch_async(globel, ^{
        //通过cgimage创建一个ciimage,用于滤镜处理的蓝本
        CIImage* ci = [CIImage imageWithCGImage:[imageV.image CGImage]];
        //通过url地址来获取一张图片,并创建ciimage用于滤镜处理的蓝本
        CIImage* ci1 = [CIImage imageWithContentsOfURL:nil];
        //通过nsdata获取一张图片,并创建ciimage用于滤镜处理的蓝本
        CIImage* ci2 = [CIImage imageWithData:nil];
        //通过cvpixel取得每一帧的图片,用于视频使用滤镜功能
        CIImage* ci3 = [CIImage imageWithCVPixelBuffer:nil];
        /*
         系统所有滤镜的详细介绍在官方文档:https://developer.apple.com/library/ios/#documentation/GraphicsImaging/Reference/CoreImageFilterReference/Reference/reference.html#//apple_ref/doc/uid/TP40004346
         */
        //创建一个滤镜,名为CICircularScreen,有黑白效果

        CIFilter* filter = [CIFilter filterWithName:@"CICircularScreen"];
        //设置滤镜所有属性用默认值,如果想修改每个属性的值,可以参考官网文档
        [filter setDefaults];
        //设置滤镜用于哪个ciimage对象,要被处理的图片
        [filter setValue:ci forKey:@"inputImage"];
        //返回添加了滤镜后的ciimage,ciimage添加滤镜后不会马上渲染,只有当使用cicontext才进行渲染,返回的ciimage是建立在一个滤镜链中的,滤镜是可以叠加使用的
        CIImage* new = [filter outputImage];
        //创建一个cicontext用于渲染图片,因为cicontext的创建成本很高,所以对于使用相同渲染技术的图片都可以使用同一个cicontext来处理。cicontext有cpu和gpu渲染两种方式
        /*
         创建一个Core Image Context
         要渲染图像,你需要创建Core Image Context,并使用这个上下文绘制输出图像。
         一个Core Image context标识一个绘制的目标。目标决定了使用CPU还是GPU去渲染。
         创建的函数:
         contextWithOptions: CPU或GPU都支持。
         以下仅支持GPU:
         contextWithCGLContext: pixelFormat:options: GPU OS X
         contextWithCGLContext: pixelFormat:
         colorSpace:options:
         
         [1] 在iOS上创建一个Core Image Context,When You Don’t Need Real-Time
         Performance
         源码:
         CIContext *context = [CIContext contextWithOptions:nil];
         这个方法可以使用CPU或者GPU进行渲染。要定义使用哪个,需要设置一个选项字典,增加键kCIContextUserSoftwareRenderer,并设置相应的布尔值。CPU渲染要比GPU要慢。但是对于GPU渲染,在渲染结果被拷贝回CPU内存并转化为UIImage之前,不会被显示出来。
         
         [2] 在iOS上创建一个Core Image Context,When You Need Real-Time Performance
         如果你的应用要支持实时的图像处理,你需要从一个EAGL context创建一个CIContext对象,不能使用contextWithOptions: 方法。优点是渲染的图像保存在GPU上,并不需要拷贝回CPU内存。你首先需要创建一个EAGL context:
         myEAGLContext = [EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
         之后使用方法contextWithEAGLContext: 创建一个CIContext对象。
         你应该将working color space设置为null,来关闭颜色管理功能。颜色管理会降低性能。在需要颜色保真的情况下,你才需要颜色管理。但是对于一个real-time app,颜色保真通常并不是必要的。
         代码:
         NSMutableDictionary *options = [NSMutableDictionary alloc] init];
         [options setObject: [NSNull null] forKey: kCIContextWorkingColorSpace];
         myContext = [CIContext contextWithEAGLContext:myEAGLContext options:options];
         */

        //使用gpu渲染
//        NSMutableDictionary *options = [[NSMutableDictionary alloc] init];
//        [options setObject: [NSNull null] forKey: kCIContextWorkingColorSpace];
//        CIContext* context =  [CIContext contextWithEAGLContext:[[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2] options:options];
        //使用cpu渲染
        CIContext* context = [CIContext contextWithOptions:nil];
        //通过cicontext渲染产生新的图片,ciimage的extent属性相当于bounds属性,代表图片的大小
        CGImageRef filterimge = [context createCGImage:new fromRect:new.extent];
        dispatch_queue_t main = dispatch_get_main_queue();
        dispatch_async(main, ^{
            imageV.image = [UIImage imageWithCGImage:filterimge];
        });
        
    });
    /*
     extern NSString *kCICategoryDistortionEffect;
     extern NSString *kCICategoryGeometryAdjustment;
     extern NSString *kCICategoryCompositeOperation;
     extern NSString *kCICategoryHalftoneEffect;
     extern NSString *kCICategoryColorAdjustment;
     extern NSString *kCICategoryColorEffect;
     extern NSString *kCICategoryTransition;
     extern NSString *kCICategoryTileEffect;
     extern NSString *kCICategoryGenerator;
     extern NSString *kCICategoryReduction;
     extern NSString *kCICategoryGradient;
     extern NSString *kCICategoryStylize;
     extern NSString *kCICategorySharpen;
     extern NSString *kCICategoryBlur;
     extern NSString *kCICategoryVideo;
     extern NSString *kCICategoryStillImage;
     extern NSString *kCICategoryInterlaced;
     extern NSString *kCICategoryNonSquarePixels;
     extern NSString *kCICategoryHighDynamicRange ;
     extern NSString *kCICategoryBuiltIn;
     */
    //通过系统提供的滤镜类别,获取类别下的所有滤镜名字,其中kCICategoryBuiltIn表示系统内建的所有类别

    NSArray* filters =  [CIFilter filterNamesInCategory:kCICategoryBuiltIn];
    for (NSString* name in filters) {
        NSLog(@"filter name:%@",name);
        //通过滤镜名字获取对应的滤镜对象
        CIFilter* filter = [CIFilter filterWithName:name];
        NSDictionary* attributes = [filter attributes];
        /*
         extern NSString *kCIAttributeFilterName;
         extern NSString *kCIAttributeFilterDisplayName;
         extern NSString *kCIAttributeFilterCategories;
         extern NSString *kCIAttributeClass;
         extern NSString *kCIAttributeType;
         extern NSString *kCIAttributeMin;
         extern NSString *kCIAttributeMax;
         extern NSString *kCIAttributeSliderMin;
         extern NSString *kCIAttributeSliderMax;
         extern NSString *kCIAttributeDefault;
         extern NSString *kCIAttributeIdentity;
         extern NSString *kCIAttributeName;
         extern NSString *kCIAttributeDisplayName;
         */
        //通过属性的key,可以获取相对应的滤镜的属性值

        NSLog(@"attributes:%@",attributes);
    }

使用滤镜前后效果如下:

CoreImage图片滤镜效果详解_第1张图片

系统自带的增益效果滤镜,用于优化拍摄后的图片


           //获取系统提供的自动增益滤镜,并把提供的所有自动增益滤镜应用的图片中,用于优化图片
        NSArray* autoAdjust = [ci autoAdjustmentFilters];
        //通过配置参数设置自动增益滤镜选择使用哪里自带滤镜
        /*
         使用自动增强滤镜
         自动增强API仅有2个方法: autoAdjustmentFilters和
         autoAdjustmentFiltersWithOptions:. 在大多数情况下,你会使用带有选项字典参数的方法。
         你可以做以下设置:
         - 对于CIRedEyeCorrection和CIFaceBalance 滤镜,图像的方向是很重要的,所以Core Image 可以精确的定位到脸。
         - 是否仅应用红眼校正。(把kCIImageAutoAdjustEnhance设置为false)
         - 是否使用红眼以外的全部其他滤镜。(把kCIImageAutoAdjustRedEye设置为false)
         
         //红颜检测以外的其他增益
         CORE_IMAGE_EXPORT NSString *kCIImageAutoAdjustEnhance __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_5_0);
         
         //红眼检测增益
         CORE_IMAGE_EXPORT NSString *kCIImageAutoAdjustRedEye __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_5_0);
         */


        //NSArray* autoAdjust = [ci autoAdjustmentFiltersWithOptions:nil];
        for (CIFilter* filter in autoAdjust) {
            NSLog(@"auto filter name:%@",[[filter attributes]valueForKey:kCIAttributeFilterName]);
            [filter setValue:ci forKey:@"inputImage"];
            ci = [filter outputImage];
        }
        CGImageRef autoimage = [context createCGImage:ci fromRect:ci.extent];
        dispatch_queue_t main = dispatch_get_main_queue();
        dispatch_async(main, ^{
            imageV.image = [UIImage imageWithCGImage:autoimage];
        });


自定义滤镜:

#import "MyFilter.h"

@implementation MyFilter
@synthesize inputImage;
@synthesize output;
- (CIImage *) outputImage {
    CIFilter* filter = [CIFilter filterWithName:@"CICircularScreen"];
    [filter setDefaults];
    [filter setValue:self.inputImage forKey:@"inputImage"];
    self.output = [filter outputImage];
    CIFilter* f1 = [CIFilter filterWithName:@"CIColorInvert"];
    [f1 setDefaults];
    [f1 setValue:self.output forKey:@"inputImage"];
    self.output = [f1 outputImage];
    return self.output;
}

@end

CoreImage图片滤镜效果详解_第2张图片

你可能感兴趣的:(CoreImage图片滤镜效果详解)