说三道四技术文摘-感悟人生的经典句子
说三道四 > 文档快照

详解OS X和iOS图像处理框架Core Image

HTML文档下载 WORD文档下载 PDF文档下载
本文结合实例详解了OS X和iOS图像处理框架Core Image的使用,如何通过Core Image来创建和使用iOS的内置滤镜,非常适合初学者学习。虽然示例代码是用Swift写的iOS程序,不过实现概念很容易转换到Objective-C和OS X。

这篇文章会为初学者介绍一下Core Image,一个OS X和iOS的图像处理框架。

如果你想跟着本文中的代码学习,你可以在GitHub上下载示例工程。示例工程是一个iOS应用程序,列出了系统提供的大量图像滤镜以供选择,并提供了一个用户界面用来调整参数并观察效果。

虽然示例代码是用Swift写的iOS程序,不过实现概念很容易转换到Objective-C和OS X。

基本概念

说到Core Image,我们首先需要介绍几个基本的概念。

一个滤镜是一个对象,有很多输入和输出,并执行一些变换。例如,模糊滤镜可能需要输入图像和一个模糊半径来产生适当的模糊后的输出图像。

一个滤镜图表是一个链接在一起的滤镜网络(无回路有向图),使得一个滤镜的输出可以是另一个滤镜的输入。以这种方式,可以实现精心制作的效果。我们将在下面看到如何连接滤镜来创建一个复古的拍照效果。

熟悉Core Image API

有了上述的这些概念,我们可以开始探索Core Image的图像滤镜细节了。

Core Image架构

Core Image有一个插件架构,这意味着它允许用户编写自定义的滤镜并与系统提供的滤镜集成来扩展其功能。我们在这篇文章中不会用到Core Image的可扩展性;我提到它只是因为它影响到了框架的API。

Core Image 是用来最大化利用其所运行之上的硬件的。每个滤镜实际上的实现,即内核,是由一个GLSL(即OpenGL的着色语言)的子集来书写的。当多个滤镜连接成一个滤镜图表,Core Image便把内核串在一起来构建一个可在GPU上运行的高效程序。

只要有可能,Core Image都会把工作延迟。通常情况下,直到滤镜图表的最后一个滤镜的输出被请求之前都不会发生分配或处理。

为了完成工作,Core Image需要一个称为上下文(context)的对象。这个上下文是框架真正工作的地方,它需要分配必要的内存,并编译和运行滤镜内核来执行图像处理。建立一个上下文是非常昂贵的,所以你会经常想创建一个反复使用的上下文。接下来我们将看到如何创建一个上下文。

查询可用的滤镜

Core Image滤镜是按名字创建的。要获得系统滤镜的列表,我们要向Core Image的kCICategoryBuiltIn类别请求得到滤镜的名字:

let filterNames = CIFilter.filterNamesInCategory(kCICategoryBuiltIn) as [String]

iOS上可用的滤镜列表非常接近于OS X上可用滤镜的一个子集。在OS X上有169个内置滤镜,在iOS上有127个。

通过名字创建一个滤镜

现在,我们有了可用滤镜的列表,我们就可以创建和使用滤镜了。例如,要创建一个高斯模糊滤镜,我们传给CIFilter初始化方法相应的名称就可以了:

let blurFilter = CIFilter(named:"CIGaussianBlur") 

设置滤镜参数

由于Core Image的插件结构,大多数滤镜属性并不是直接设置的,而是通过键值编码(KVC)设置。例如,要设置模糊滤镜的模糊半径,我们使用KVC来设置inputRadius属性:

blurFilter.setValue(10.0 forKey:"inputRadius")

由于这种方法需要AnyObject? (即Objective-C里的id)作为其参数值,它不是类型安全的。因此,设置滤镜参数需要谨慎一些,确保你传值的类型是正确的。

查询滤镜属性

为了知道一个滤镜提供什么样的输入和输出参数,我们就可以分别获取inputKeys和outputKeys数组。它们都返回NSString的数组。

要获取每个参数的详细信息,我们可以看看由滤镜提供的attributes字典。每个输入和输出参数名映射到它自己的字典里,描述了它是什么样的参数,如果有的话还会给出它的最大值和最小值。例如,下面是 CIColorControls滤镜对应的inputBrightness参数字典:

inputBrightness = {      CIAttributeClass = NSNumber;    CIAttributeDefault = 0;    CIAttributeIdentity = 0;    CIAttributeMin = -1;    CIAttributeSliderMax = 1;    CIAttributeSliderMin = -1;    CIAttributeType = CIAttributeTypeScalar;};

对于数值参数,该字典会包含 kCIAttributeSliderMin 和 kCIAttributeSliderMax 键,来限制期望的输入域。大多数参数还包含一个 kCIAttributeDefault 关键字,映射到该参数的默认值。

图片滤镜实战

图像滤镜的工作由三部分组成:构建和配置滤镜图表,发送等待滤镜处理的图像,得到滤镜处理后的图像。下面的部分对此进行了详细描述。

构建一个滤镜图表

构建一个滤镜图表由这几个部分组成:实例化我们需要的滤镜,设置它们的参数,把它们连接起来以便该图像数据按顺序传过每个滤镜。

在本节中,我们将创建一个用来制作 19 世纪锡版照风格图像的滤镜图表。我们将两个效果链在一起来达到这种效果:同时去饱和以及染色调的黑白滤镜,和一个暗角滤镜来创建一个有阴影效果的加框图片。

用Quartz Composer,来做Core Image滤镜图表的原型非常有用,可以从苹果开发者网站下载。下面,我们整理了所需的照片滤镜,把黑白滤镜和暗角滤镜串在一起:


一旦达到了我们满意的效果,我们可以重新在代码里创建滤镜图表:

let sepiaColor = CIColor(red: 0.76, green: 0.65, blue: 0.54)  let monochromeFilter = CIFilter(name: "CIColorMonochrome",      withInputParameters: ["inputColor" : sepiaColor, "inputIntensity" : 1.0])monochromeFilter.setValue(inputImage, forKey: "inputImage")let vignetteFilter = CIFilter(name: "CIVignette",      withInputParameters: ["inputRadius" : 1.75, "inputIntensity" : 1.0])vignetteFilter.setValue(monochromeFilter.outputImage, forKey: "inputImage")let outputImage = vignetteFilter.outputImage

需要注意的是黑白滤镜的输出图像变为暗角滤镜的输入图像。这将导致暗角效果要应用到黑白图像上。还要注意的是,我们可以在初始化中指定参数,而不一定需要用KVC单独设置它们。

创建输入图像

Core Image滤镜要求其输入图像是CIImage类型。而对于iOS的程序员来说这可能会有一点不寻常,因为他们更习惯用UIImage,但这个区别是值得的。一个CIImage实例实际上比UIImage更全面,因为CIImage可以无限大。当然,我们不能存储无限的图像在内存中,但在概念上,这意味着你可以从2D平面上的任意区域获取图像数据,并得到一个有意义的结果。

所有我们在本文中使用的图像都是有限的,而且也可以很容易从一个UIImage来创建一个CIImage。事实上,这只需要一行代码:

let inputImage = CIImage(image: uiImage)

也有很方便的初始化方法直接从图像数据或文件URL来创建CIImage。

一旦我们有了一个CIImage,我们就可以通过设置滤镜的inputImage参数来将其设置为滤镜的输入图像:

filter.setValue(inputImage, forKey:"inputImage")

得到一个滤镜处理后的图片

滤镜都有一个名为outputImage的属性。正如你可能已经猜到的一样,它是 CIImage 类型的。那么,我们如何实现从一个CIImage创建UIImage这样一个反向操作?好了,虽然我们到此已经花了所有的时间建立一个滤镜图表,现在是调用CIContext的力量来实际的做图像滤镜处理工作的时候了。

创建一个上下文最简单的方法是给它的构造方法传一个nil字典:

let ciContext = CIContext(options: nil)

为了得到一个滤镜处理过的图像,我们需要CIContext从输出图像的一个矩形内创建一个CGImage,传入输入图像的范围(bounds):

let cgImage = ciContext.createCGImage(filter.outputImage, fromRect: inputImage.extent())

我们使用输入图像大小的原因是,输出图像通常和输入图像具有不同的尺寸比。例如,一个模糊图像由于采样超出了输入图像的边缘,围绕在其边界外还会有一些额外的像素。

现在,我们可以从这个新创建的CGImage来创建一个UIImage了:

let uiImage = UIImage(CGImage: cgImage)

直接从一个CIImage创建UIImage也是可以的,但这种方法有点让人郁闷:如果你试图在一个UIImageView上显示这样的图像,其contentMode属性将被忽略。使用过渡的CGImage则需要一个额外的步骤,但可以省去这一烦恼。

用OpenGL来提高性能

用CPU来绘制一个CGImage是非常耗时和浪费的,它只将结果回传给UIKit来做合成。我们更希望能够在屏幕上绘制应用滤镜后的图像,而不必去Core Graphics里绕一圈。幸运的是,由于OpenGL和Core Image的可互操作性,我们可以这么做。

要OpenGL上下文和Core Image上下文之间共享资源,我们需要用一个稍微不同的方式来创建我们的 CIContext:

let eaglContext = EAGLContext(API: .OpenGLES2)  let ciContext = CIContext(EAGLContext: context)

在这里,我们用OpenGL ES 2.0的功能集创建了一个EAGLContext。这个GL上下文可以用作一个GLKView的背衬上下文或用来绘制成一个CAEAGLLayer。示例代码使用这种技术来有效地绘制图像。

当一个CIContext具有了关联GL的上下文,滤镜处理后的图像就可用OpenGL来绘制,像如下这样调用方法:

ciContext.drawImage(filter.outputImage, inRect: outputBounds, fromRect: inputBounds)

与以前一样,fromRect 参数是用滤镜处理后的图像的坐标空间来绘制的图像的一部分。这个inRect 参数是GL上下文的坐标空间的矩形应用到需要绘制图像上。如果你想保持图像的长宽比,你可能需要做一些数学计算来得到适当的inRect。

强制在CPU上做滤镜操作

只要有可能,Core Image将在GPU上执行滤镜操作。然而,它确实有回滚到CPU上执行的可能。滤镜操作在CPU上完成可具有更好的精确度,因为GPU经常在浮点计算上以失真换得更快的速度。在创建一个上下文时,你可以通过设置kCIContextUseSoftwareRenderer关键字的值为true来强制Core Image在CPU上运行。

你可以通过在Xcode中设置计划配置(scheme configuration)里的CI_PRINT_TREE环境变量为1来决定用CPU  还是GPU来渲染。这将导致每次一个滤镜处理图像被渲染的时候Core Image都会打印诊断信息。此设置用来检查合成图像滤镜树也很有用。

示例应用一览

本文的示例代码是一个iPhone应用程序,展示了iOS里大量的各式Core Image图像滤镜。

为滤镜参数创建一个GUI

为了尽可能多的演示各种滤镜,示例应用程序利用了Core Image的内省特点生成了一个界面,用于控制它支持的滤镜参数:


示例应用程序只限于单一的图像输入以及零个或多个数值输入的滤镜。也有一些有趣的滤镜不属于这一类(特别是那些合成和转换滤镜)。即便如此,该应用程序仍然很好的概述了Core Image支持的功能。

对于每个滤镜的输入参数,都有一个滑动条可以用于配置参数的最小值和最大值,其值被设置为默认值。当滑动条的值发生变化时,它把改变后的值传给它的 delegate,一个持有CIFilter引用的 UIImageView子类。

使用内建的照片滤镜

除了许多其他的内置滤镜,示例应用程序还展示了iOS 7中引入的照片滤镜。这些滤镜没有我们可以调整的参数,但它们值得被囊括进来,因为它们展示了如何在iOS中模拟照片应用程序的效果:


结论

这篇文章简要介绍了Core Image这个高性能的图像处理框架。我们一直在试图在如此简短的形式内尽可能多的展示这个框架的功能。你现在已经学会了如何实例化和串联Core Image的滤镜,在滤镜图表传入和输出图像,以及调整参数来获得想要的结果。你还学习了如何访问系统提供的照片滤镜,用以模拟在iOS上的照片应用程序的行为。

现在你知道了足够多的东西来写你自己的照片编辑应用程序了。随着更多的一些探索,你就可以写自己的滤镜了,利用你的Mac或iPhone的神奇的力量来执行以前无法想象的效果。快去动手做吧!

参考

  • Core Image Reference Collection是Core Image的权威文档集。
  • Core Image Filter Reference包含了Core Image提供的图像滤镜的完整列表,以及用法示例。
  • 如果想要写更函数式风格的Core Image代码,可以看看Florian Kluger在objccn.io话题#16里的文章。
本文转载自:objccn

移动周报:两岸三地在线编程学习网站大搜罗 有道周枫和他的“放养”团队 看IE11如何助力AAF推动公益事业 SUSE总裁Nils:将SUSE Cloud 2.0打造成“零影响的云安装程序” Windows 8之父Steven Sinofsky:2014年科技界的十大趋势 电视盒子还没智能化?看Fan TV们怎么玩 畅游启动“必赢计划” 十亿巨资代理优质产品 数据控使用Hadoop的三种最常用方式 值得创始人学习的五大企业文化管理方式 圣诞节快乐:来自程序员们的问候 宏碁任命新CEO Jason Chen:曾任职英特尔14年、台积电8年 史上第一次越狱发布会与Evad3rs太极助手罗生门 新东方在线CTO曾明:已用Cocos2d-html5开发出150余款产品 Facebook 2013年的9个开源项目 开源力量公开课2013年度庆典:我们的开源项目 看雪学院“走进企业看安全”活动走进安全管家 视频+PPT:苹果iOS7 Tech Talks大会演讲内容 iPhone 6和Galaxy S5暂不会采用弯曲屏技术 当程序不工作时,开发者常用的借口 携程技术副总裁叶亚明:三次重大技术改进的故事及背后原因 Google抛弃C语言,采用Go语言重写Go编译器 jQuery Mobile 1.4.0正式版发布,着重性能改进 IBM收购Aspera加速大数据传输 各式各样的极品程序员,你属于哪一种 Google员工离职前必做的14件事情 GitHub上最火的开源项目及编程语言是什么? 2014的12个大数据趋势:Hadoop继续升温,R将进入主流 研究称三星手机可能存在安全漏洞 初创IT公司里开发者最容易犯的九种错误 还有多少开发者在为IE6做兼容性测试? 解读华三“新IT易之道”理念下的云计算和数据中心 请大侠帮我解决一个数据库的问题 请问如何操作分布在两个数据库中的表数据? 寻求合作(有关车间数据采集):谁要MONEY? 请问哪里有有关COM原理的Ebook可以下载???? 有谁能够告诉我有关网站发展历史的资料么?世界上第一个网站是怎样建成的?以后的发展脉络呢?如果有谁能够相告不胜感激啊。 讨论:可视化开发XSLT的工具!! 如何使用VC进行“毫秒级”以下的 定时器。即(xx uS 的定时器)。。。。。。。。。。。。 看电视(转载) jsp比asp,php等好么?(在线等候) 怎样实现图像的自动拼接? 报表输出问题 我用ActionManage做出的菜单为何汉字显示总是最后一个字少半边? c#里如何使用shbrowseforfolder?那位兄弟给个例子 如何实现MAC和IP绑定。 帮帮我啊,老大们我真的很急谢了 session问题?????? 报表输出问题 你愿意吗? 关于PB中做VFP的ODBC的一个问题 我为什么不能提问? 在PASCAL语言中的"集合"概念,转化到C语言中,该怎么实现? 帮我看一下这个程序. 谁人发个QB的编辑器给我? 如何改变应用程序的图标 网吧管理 帮我看一下这个程序. 谁看谁头疼的问题!你除外! 请问JDK和J2SDK有什么区别? win98 转 win2000出现的问题,急,再线等候! 停止函数执行 请问如何在鼠标点击xx button 的时候获得 JtextField 中的文本输入--有重分送 我不能关机了!救救我哟~~给你分! tomcat4.0.1无法启动的问题 SoS!俺用fireworks做了一套菜单,但是应用于框架结构中时,只显示菜单所在框架的部分菜单。也就是说菜单显示不完整,如何能够让菜单跨越 刚装了REDHAT 7.2,不知道网络怎么设置 报表打印,望各位指点..... 是不是我这里设错了? 菜鸟有问题,Win2k的定时关机程序 关于天数累加的问题 webbrowser控件问题? 421连续进纸标准,打印问题,难啊,难 有个小问题难住偶了! 请教 bdf 文件的格式 在JPrint中如何设置页面的打印范围(不使用打印机的默认打印范围),找不到例子,那位能够给个实例。。。 开发jsp需要什么环境和安装软件,目前版本为多少? 在PASCAL语言中的"集合"概念,如何转化成C语言表示 怎么回事。formshow 不能写太多sql语句么〉?,怎么不显示?大家快帮看看,急死了 自动累加的问题?(100)我只能给这么多了 哪里可以下载powerbuilder7.0 网页自动累加的问题(100) help 数学中√表示什么啊 如图,在以O为圆心的两个同心圆中,AB经过圆心O,且与小圆相交于点A,与大圆相交于点B,小圆的切线AC与大圆相交于点D,且CO平分∠ACB.(1)试判断BC所在直线与小圆的位置关系,并说明理由;(2) 用狐狸,小山羊和小白兔. 我想问下数学中“^”代表了什么 如图,在以O为为圆心的两个同心圆中,AB经过圆心O,且与小圆相交于点A,与大圆相交于点B.小圆的切线AC与大圆相交于点D,且CO平分∠ACD.(1)试判断BC所在直线与小圆的位置关系,并说明理由.(2) 用小白兔,胡萝卜和山羊编童话故事 500字 火车转弯向心力如何得到 角铝规格6*60*60,长度是2636,怎么计算价格啊? 40(?)+20(?)=1(?)填单位! 3(4):火车在转弯时 受向心力作用,对其所受向心力分析正确的是( )B.主要由于内外轨的高度差的作用,车身略有倾斜,车身所受重力的分力产生了向心力请问上述B选项分析是否正确?为什么? 刺猬汉斯是-----国作家-------写的————(体裁)我还读过他们其他的童话,有,< > 《 》《 》等. 一棵树高20( )填单位 火车转弯时的向心力类型问题真心不会 刺猬汉斯的主要内容是什么? 若二次函数y=f(x)的图像经过原点,且1≤f(-2)≤2,3≤f(1)≤4.求f(2)的取值范围 /在数学中代表什么? 刺猬汉斯讲了几件事,都什么事? 分米的英文符号是什么? 在数学中∧代表什么 《刺猬汉斯》是《格林童话》写的. 改病句 若已知二次函数y=f(x)的图象过原点,且1 ∧这个在数学中代表什么? 刺猬汉斯帮我分段啊! 分米的符号怎么表示? 解释一下火车转弯时外轨和内轨等高和不等高时向心力分别由什么力来提供 【高中物理必修二向心力】火车最佳速度问题中 重力和支持力的合力等于向心力;那么摩擦力呢 是不是没有办法算 所以算这个合力只能通过重力算 不能先把重力正交分解成支持力和静摩擦 会计判断题 1.“短期借款”账户不核算应支付的借款利息.2、银行借款不论期限长短都必须按期偿还,并按规定支付利息.3、企业计提固定资产折旧时,应借记“累计折旧”账户,贷方“固定资产 猴子的屁股为什么是红的写一篇童话故事 为什么火车拐弯时,支持力所提供的向心力是水平的而非其他方向?火车拐弯时除前进方向还有其他摩擦力吗? 求这些会计的判断题答案,最好能说明错在哪里 1.用银行存款去归还银行贷款,属于“一种形式的资产减少,引起另一种形式的负债减少”.2.按会计核算原则,凡是支出的效益仅与本会计年度 汽车转弯时的向心力是静摩擦力提供的,静摩擦力的方向应该是与相对运动趋势相反,而汽车转弯时若不受外力则物体会沿切线方向继续运动,可推的其相对运动趋势应为其切线方向.那为什么静 豆浆里的油条打一歇后语.提示是两个字的. 点A在半径为1且圆心在原点的圆上,且角AOx=45度,点P从A点出发,逆时针等速沿着单位圆旋转已知P在1秒内转过的角度为M(0度 在恶补微积分,我目前大一,希望高手们求救!有什么用的?怎么很多式子都有? 如今的专家些,牛奶和鸡蛋,豆浆和油条都不能搭配!那娃娃现在早餐还能吃啥呢? 如图,在平面直角坐标系xoy中,直线AB过点A(-4,0),B(0,4),圆的半径为1原点为圆心,点P在直线AB上,过点P作圆的一条切线PQ,Q为切点,则切线长PQ的最小值为? 在数学上面X代表什么意思 数学速度是用v表示吗? 如图,以原点为圆心的圆的直径AB= /代表什么数学意思 V代表什么? 如图,在平面直角坐标系中,半径为1的圆的圆心O在坐标原点,且与两座标轴分别交于A/B如图,在平面直角坐标系中,半径为1的圆的圆心O在坐标原点,且与两座标轴分别交于A、B、C、D四点,抛物线y=ax 《时间老人与穿衣镜》是童话还是寓言? v是在古代数学中代表几 童话故事,200字左右的 时光老人与穿衣镜时光老人和穿衣镜明亮的穿衣镜四平八稳地立在过道里,来来往往的人们都向她投去亲切而期待的目光,她总是忠实地反映出人们的容貌和衣着.一天,时光老人路过这里,镜子 小性人怎么交往 跨度9米,用那种规格H型钢能承受10吨的重量柱子与柱子距离是9米,上面铺导轨,10T双梁起重机在上面跑.H型钢用多大16T天车 ,柱子与柱子距离是9米,9米的跨度轨道梁应该是多大的,上面是16T天车 时光老人与穿衣镜的问题答案 已知:如图,圆心C过原点,并与坐标轴分别交于点A,D,∠OBA=30°,点D的坐标为(0,3),求点A,C的坐标求点A,C的坐标 如图在以O为原点的直角坐标系中,点A,C分别在X轴,Y轴的正半轴上,点B(a,b)在第一象限一四边形OABC,反比例函数y=分之k(k>0,x>0)的图像与AB相交于点D,与BC相交于点E,且BE=CE(1)试说明:BD=AD(2) 时光老人和穿衣镜告诉我们什么道理 买2根油条1杯豆浆一共8元4角钱,油条上涨50%豆浆上涨20%一共9元6角钱. 以平面直角坐标系的原点O为圆心以1为半径作圆若点P是是该圆上第一象限内的一点且OP与X轴正方向组成角R则点则点P的坐标为 《时光老人与穿衣镜》的读后感在1月10日之前我万分感谢. 解决几道判断题,顺便讲解一下对或错的理由1、将一个半径为rcm的圆形纸片切割成若干等份后拼成长方形,长方形的长是π rcm ( )2、r的平方=r×r=2r ( ) 如图,在以O为原点的直角坐标系中,点A、C分别在x轴、y轴的正半轴上,点B(a,b)在第一象限,四边形OABC是矩形,若反比例函数y=k/x的图像经过ab边的中点f,交bc边与点e (1)求证be=ce(2)若四边形oe ⊙在数学里代表啥 1、准确数18精确到个位,2、四舍五入奖3.995精确的百分卫是4.00 市场营销判断题~无差异性市场营销战略完全不符合现代市场营销理论.市场定位、产品定位和竞争性定位分别有不同的含义.企业在市场营销方面的核心能力与优势,会自动地在市场得到表现.
备案号:鲁ICP备13029499号-2 说三道四 www.s3d4.cn 说三道四技术文摘