在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);
}
使用滤镜前后效果如下:
系统自带的增益效果滤镜,用于优化拍摄后的图片
//获取系统提供的自动增益滤镜,并把提供的所有自动增益滤镜应用的图片中,用于优化图片
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