ios滤镜Core Image

Core Image 是一个很强大的框架。

它可以让你简单地应用各种滤镜来处理图像,比如修改鲜艳程度, 色泽, 或者曝光。 

它利用GPU(或者CPU,取决于客户)来非常快速、甚至实时地处理图像数据和视频的帧。

多个Core Image滤镜可以叠加在一起,从而可以一次性地产生多重滤镜效果。这种多重滤镜的优点在于它可以生成一个改进的滤镜,从而一次性的处理图像达到目标效果,而不是对同一个图像顺序地多次应用单个滤镜。每一个滤镜都有属于它自己的参数。这些参数和滤镜信息,比如功能、输入参数等都可以通过程序来查询。用户也可以来查询系统从而得到当前可用的滤镜信息。

到目前为止,Mac上只有一部分Core Image滤镜可以在iOS上使用。但是随着这些可使用滤镜的数目越来越多,API可以用来发现新的滤镜属性。


Core Image 总览

开始之前,让我们谈谈Core Image框架中最重要的几个类:

  • CIContext. 所有图像处理都是在一个CIContext 中完成的,这很像是一个Core Image处理器或是OpenGL的上下文。
  • CIImage. 这个类保存图像数据。它可以从UIImage、图像文件、或者是像素数据中构造出来。
  • CIFilter. 滤镜类包含一个字典结构,对各种滤镜定义了属于他们各自的属性。滤镜有很多种,比如鲜艳程度滤镜,色彩反转滤镜,剪裁滤镜等等。

在新建一个项目过程中,你会依次用到这些类。

让我们开始吧

打开Xcode, 用iOS Application ->Single View Application 模板创建一个项目。输入CoreImageFun作为产品的名字。选择iPhone作为设备类型,并且确保只勾选Use StoryboardsUse Automatic Reference Counting两个选项。

首先,让我们导入Core Image框架。在Mac上,这个过程是QuartzCore框架的一部分;但是在iOS上,这个是单独的一个框架。在左侧文件导航栏中,进入项目文件夹。选择Build Phases标签页,扩展Link Binaries和Library group, 点击“+”来添加按钮;找到CoreImage框架并且双击完成添加。

第二步,下载教程资源,把其中的image.png添加到项目中,我们的创建设置就完成了。

之后,打开MainStoryboard.storyboard, 把图像视图拖拽到视图控制器中,并把它的模式设定为Aspect Fit使得它的位置和维度近似如下图所示:


同时,打开Assistant Editor,确保编辑器显示ViewController.h, 并从UIImageView拖拽到@interface以下。把Connection设置到指向Outlet, 并命名为imageView,之后点击Connect进行连接。

编译运行来确保到目前为止每一步都是正确的。如果一切正常,你将会看到一个空屏幕。这时,我们的初始化设置就完成了,下面我们就进入Core Image部分!

基本的图像滤镜

作为第一个尝试,我们先简单的让图像通过一个CIFilter 之后显示在屏幕上。每一次当我们想应用一个CIFilter的时候都要有以下四个步骤:

  1. 创建一个 CIImage 对象: CIImage 有如下的初始化方法: imageWithURL:, imageWithData:, imageWithCVPixelBuffer:, 和 imageWithBitmapData:bytesPerRow:size:format:colorSpace:。但是大多数时候你只会经常用到imageWithURL。
  2. 创建一个 CIContext: 一个 CIContext 可以是基于CPU或是GPU的。它可以被重用,所以你不用每次都创建一个。但是当输出CIImage对象的时候你至少一定会需要一个CIContext。
  3. 创建一个CIFilter: 当你创建滤镜的时候,你可以在上面配置一定数量的属性。具体的属性取决于你所要用的滤镜。
  4. 输出滤镜:这个滤镜会输出一个图像成为CIImage。 你可以用CIContext把它转化为一个UIImage ,具体过程如下。

让我们看看这是如何实现的。把下面的代码加入到viewDidLoad中的ViewController.m里面。

[html]  view plain copy
  1. // 1  
  2. NSString *filePath =  
  3.   [[NSBundle mainBundle] pathForResource:@"image" ofType:@"png"];  
  4. NSURL *fileNameAndPath = [NSURL fileURLWithPath:filePath];  
  5.   
  6. // 2  
  7. CIImage *beginImage =  
  8.   [CIImage imageWithContentsOfURL:fileNameAndPath];  
  9.   
  10. // 3  
  11. CIFilter *filter = [CIFilter filterWithName:@"CISepiaTone"  
  12.                               keysAndValues: kCIInputImageKey, beginImage,  
  13.                     @"inputIntensity", @0.8, nil];  
  14. CIImage *outputImage = [filter outputImage];  
  15.   
  16. // 4  
  17. UIImage *newImage = [UIImage imageWithCIImage:outputImage];  
  18. self.imageView.image = newImage;  

让我们依次看看这些代码都做了什么事情

  1. 前两行创建了一个NSURL 对象, 包含指向图形文件的路径。
  2. 下面,用imageWithContentsOfURL方法创建CIImage。
  3. 之后,创建CIFilter对象。一个 CIFilter 构造函数有两个输入,分别是滤镜的名字,还有规定了滤镜属性的键值和取值的字典。 每一个滤镜会有它自己唯一的键值和一组有效的取值。CISepiaTone 滤镜只能选两个值: KCIInputImageKey (一个CIImage) 和 @”inputIntensity”。 后者是一个封装成NSNumber (用新的文字型语法)的浮点小数,取值在0和1 之间。大部分的滤镜有默认值,只有CIImage是个例外。你必须提供一个值给它,因为它没有默认值。从滤镜中导出CIImage很简单,只需要用outputImage方法。
  4. 一旦你有了导出的 CIImage,你就可以把它转化为一个 UIImage。 在新的iOS6中,UIImage 方法+ imageWithCIImage方法可以实现从CIImage 到UIImage 到转化。一旦转化完成,我们就可以让UIImage 显示在之前添加的图像视图里。

编辑运行项目,你将会看到你的图片如下图一般,已经被墨色调滤镜处理过。恭喜你,你已经成功掌握并运用了CIImage和CIFilters。

把它放在上下文中

在进行下一步之前,有一个优化的方法很实用。我前面提到过,你需要一个CIContext来进行CIFilter,但是在上面的例子中我们没有提到这个对象。因为我们调用的UIImage方法(imageWithCIImage)已经自动地为我们完成了这个步骤。它生成了一个CIContext并且用它来处理图像的过滤。这使得调用Core Image的接口变得很简单。

但是,有一个主要的问题是,它的每次调用都会生成一个CIContext。CIContext本来是可以重用以便提高性能和效率的。比如下面我们要谈到的例子,如果你想用滑动条来选择过滤参数取值,每次改变滤镜参数都会自动生成一个CIContext, 使得性能非常差。

让我们想个好办法搞定这个问题。删除你之前添加到viewDidLoad里面的代码,用下面的代码取而代之:

[html]  view plain copy
  1. CIImage *beginImage =  
  2.   [CIImage imageWithContentsOfURL:fileNameAndPath];  
  3.   
  4. // 1  
  5. CIContext *context = [CIContext contextWithOptions:nil];  
  6.   
  7. CIFilter *filter = [CIFilter filterWithName:@"CISepiaTone"  
  8.                               keysAndValues: kCIInputImageKey, beginImage,  
  9.                     @"inputIntensity", @0.8, nil];  
  10. CIImage *outputImage = [filter outputImage];  
  11.   
  12. // 2  
  13. CGImageRef cgimg =  
  14.   [context createCGImage:outputImage fromRect:[outputImage extent]];  
  15.   
  16. // 3  
  17. UIImage *newImage = [UIImage imageWithCGImage:cgimg];  
  18. self.imageView.image = newImage;  
  19.   
  20. // 4  
  21. CGImageRelease(cgimg);  

再让我逐步解释一下这部分代码

  1. 在这部分代码中,你创建了CIContext对象。CIContext 构造函数的输入是一个NSDictionary。 它规定了各种选项,包括颜色格式以及内容是否应该运行在CPU或是GPU上。对于这个应用程序,默认值是可以用的。所以你只需要传入nil作为参数就好了。
  2. 在这里你用上下文对象里的一个方法来画一个CGImage。 调用上下文中的createCGImage:fromRect:和提供的CIImage可以生成一个CGImageRef。
  3. 下面,你用UIImage + imageWithCGImage,从CGImage中创建一个UIImage。
  4. 最后,开放 CGImageRef接口。 CGImage 是一个C接口,即使有ARC,也需要你自己来做内存管理。

编译运行,确保正常工作。

在这个例子中,添加CIContext的创建 和你自己来创建的区别不大。但是在下一部分中,你将会看到当你实现动态改变滤镜参数的时候的重大性能差别。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值