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

详解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

Apache Hadoop集群的安全性架构 Wood Camera开发者访谈:我们如何冲到榜首的 代码审查:程序员内炼之道 Twitter Q1推广告API 收入剑指10亿 Dell:在OpenStack成熟后才会推出服务 一个开源工作者对开源与赚钱的一些想法 宏碁:Windows8仍不成功 Chrome表现令人意外 雅虎发布Q4财报 净利润同比下滑8% 游戏机禁售令起风波,索尼任天堂股价大涨 国外开发者吐槽Facebook Android设计一例 Rovio转向发行业务 将发布新作Tiny Thief 上山下海 “硬汉”服务器无所不能 访金山云CTO杨刚:开源改进PK自主研发,技术驱动前行 苹果涉及色情问题,且进一步恶化 开源产品系列:面向组件的Web框架tapestry 360指责百度窃取用户信息 公布美杜莎插件技术分析 苹果正式发布iOS 6.1 最快本周日即可越狱 苹果高管:运行iOS 6的设备达3亿 Chrome OS 黑客大赛总奖金为314.159万美元 微软雷德蒙研究院副总裁:从计算研究到惊人发明 还驾驭不了4核? 别人已模拟出百万核心上的并行 RIM将网络直播BlackBerry 10发布会 解读TDD的五大误区 Amazon 2012财年Q4财报:电子书业务增长70% 从暴风影音CTO到创业者:画中画相机话中话 为什么Android应用开发总要比iOS晚? 传奇VC马克.安德雷森:未来的企业什么样? 呼吁国会通过“创业签证”:奥巴马助力美国招揽海外人才 Surface Pro最低1019美元,价值究竟如何? 搜狗号码通产品经理谈微创新 数据和运营更关键 在线推荐系统是如何进行工作的? 不同窗体之间如何传递变量??? 我用Internet Transfer Control 做ftp程序时遇到的问题! 我就这么点分了!谁帮我解释一下滤镜呀!那个用来处理图象的!在JAVBASCRIPT! 路由到底是什么东东,我怎么不明白怎么回事? 如何在属性页中加入静态切分视图??? 我是天津人有没有同乡? ------------------------smiled 快来 我要饿死了----------------------- 我想用DCOM实现访问数据库,请大家指点,请进 竹子, 还给我一点分吧? TO:Vincent_Jiang(无生无灭) 两机相连的问题??? 提问题给的最高分于其余的分有何关系?请问斑竹 什么叫数据库的别名,应该怎样设置数据库的别名? 怎样与telnet应用服务程序通信 怎样在TStringGrid的整个框内绘图,而不是在某个单元中绘图? WEB安全认证问题 TO: neweb(永不言败) 请问各位大虾,哪里有jdk1.3 for linux SPARC 版本 求救!硬盘坏了! 晨昏三灌水,早晚一个屁 怎么在EXCEL中用VBA控制图表的位置? Delphi确实很好,学了好几年了,但在上海差点没有找到工作,很少有招学Delphi的 关于 VC 6.0 有没有什么补丁,升级文件之类的东西? 高分争解 怎么利用Jsp发邮件? 有谁知道光驱加锁的问题 parodox数据库问题 各位平时用 VC 作东西,都用那些辅助工具?  高分争解 【 http://www.esoftware.com.cn/search.php?condition=%BA%AB%C1%F7%C0%B4%CF%AE&page=1&mode=3 】 JBuilder的使用问题 在VFP中,编程执行SQL语句时,怎样使系统的查询结果不出现? 一个程序流程的问题 为什么当我的SpeedButton的enabled为false时,上面的图标就没有了? 囡囡(baicolt)请进,问你一点事情 简单问题,请赐教 高分相赠!!!:操作系统和SQL SEVER2000都是英文版,用VB连接如何可以正确的输入和显示中文? 则么在程序中得到sql的存储过程的返回值? 请问 VB 6.0 有没有最新的升级文件之类的东西?高分争解 谢谢 谁有用java做的复杂一点的图行界面的例子 网管来看看,为什么不能给分了!右边的文本框又不见了! 各位用 VB 编程都用那些辅助工具? 高分争解 关于ShellExecute 装了redhat7,在/etc里没有inetd.conf文件,谁见过这咋整 菜鸟请教大侠!很急!谢谢!!只有10分对不起! 请问一个关于CLASSWIZARD 的问题 这里有PB反编译程序,你信吗? 怎样解 关于大数据量的问题,经验丰富者里面谈! 我想在程序里控制程序外的浏览器窗口资源管理器窗口,怎么做呢?急呀!!!!!! 请问:我用JavaMail收下的邮件主题,发信人姓名不能正常显示。。。。。 认识我的人都进来跟我聊聊吧,我最近新换了工作,还没有适应,你们各位是怎么换工作? 请问如何在Delphi中表示二进制,或者十六进制数呢? 生活中,过滤水或纯水怎么弄到?不能直接用自来水 请问为什么电解食盐水时石墨电极会剥落 为什么Na2O和Na2O2的阴阳离子个数比相同? 过滤后的水是否一定是纯水? 用石墨电极电解500ml饱和食盐水,在阴极得到的气体在标准状况下体积转为56ml假设溶液体积保持不变,求电解后溶液的ph Na2O2晶体中的阴阳离子比 过滤得到的水为什么不是纯水 现有500mL饱和食盐水,其中含有少量NaOH,该溶液的pH为10,用石墨电极电解时,当阴极产生5.6L H2(标准状况)时停止电解,此时溶液的pH约为: 向Na2O2与水完全反应后的溶液中加MnO2,产生O2,是由于该溶液中含H2O2为什么? 杀菌过滤后的水虽然澄清透明,但不是纯水如何证明他不是纯水,写出实验的步骤、现象和结论.(字数不要太多啊) 3V,石墨电极电解食盐水一段时间后溶液变黄,为什么? Na2O2与H2O反应为什么生成H2O2正常不是生成NaOH和O2嘛.为什么会生成H2O2、? 目前市场上买的净水器真有净化水的功能吗?如果安装净水器对身体有益处,什么牌子的质量过关? 由氢氧化钠(NaOH)和过氧化钠(Na2O2)组成混合物,并检测出氢元素的质量分数为1%(出5个类似的计算题)谢谢悬赏20拜托了今晚求答复 设计实验证明O2来自H2O2在H2O2+MnO2====O2↑△这个反应中请用实验证明得到的O2来自于H2O2而不是MnO2(注意,是用实验证明)我知道MnO2是催化剂 但必须用好的实验啊 纯水的标准是什么是?超纯净水的标准是什么? 帮忙出550道计算题和165道应用题 能用FeSO4溶液来检验Na2O2与足量水反应后的溶液中存在的H2O2么 纯水和净水的区别 化学Na2O2+CO21.这是放热还是吸热?2.怎么判断Na2O2和CO2中的氧在反应后变成了哪个物质中的氧啊?我的意思是,2Na2CO3中有6个氧,O2中有两个,那应该怎么判断2Na2O2中的那4个氧和2CO2中的那4个氧分 可用CO2来确定某NA2O粉末是否含有NA2O2,为什么错?不是产生O2吗? 纯净水是纯水吗? 【化学】Na2O2为什么是共价化合物?我查的到Na2O2的电子式如下:....Na+ [ :O:O:]2- Na+....过氧根显-2价,2个Na原子的电子转移到过氧根上,正好形成稳定结构.可它为什么是共用电子对的共价化合物?Na 根据Na2O与O2加热后生成Na2O2可知Na2O与Na2O2哪个更加稳定把前因后果也具体说明一下吧 我想问一下,纯净水和净化水有什么区别? Na2O2可以与哪些物质反应? 证明Na在空气中燃烧生成淡黄色粉末为Na2O2而不是Na2O 以食盐和水为反应物,经过电解制得Cl2 H2 NaO2三种物质,求该反应的化学方程式 将等物质量的 Na2CO3 ,Na2O2 ,Na2O ,NaOH ,NaHCO3 ,NaCO3-8H2O 放置于空气中将等物质量的 Na2CO3 、Na2O2 、Na2O 、NaOH 、NaHCO3 、NaCO3-8H2O 放置于空气中 ,其质量由小到大的顺序是: 为什么说NA2O在空气加热形成NA2O2比NA2O稳定 食盐水微酸性电解制得氯酸钠化学反应方程式是什么? 将Na2O NaOH Na2O2微粒数目相等的上述固体物质长期放制在空气当中,最后质量增加的大小顺序是 Na2O与Na2O2哪个是粉末哪个是晶体 电解氯化钠的化学反应方程式 NaOH,Na2O,Na2CO3,Na2O2 哪一个放在空气中,会发生氧化还原反应而变质?希望能详细解答,谢谢了! 装置I中发生反应的化学方程式为?(金属钠和空气制备纯度较高的Na2O2实验) 用铜电极电解食盐水的先后现象及相关化学方程式.谢谢! 将等质量的①na②na2o③na2o2④naoh将等质量的①Na②Na2O③Na2O2④NaOH ⑤Na2CO3·10H2O露置于空气中,最后质量由小到大的顺序是A.⑤<④<③<②<① B.①<②<③<④<⑤?C.⑤<④<②=③<①?D 现用金属钠和空气制备纯度较高的Na2O2,可利用的装置如下.回答下列问题(注:Na2O2可以与H2O、CO2能反应)(1)装置Ⅳ中盛放的药品是______________,其作用是__________________________.(2)若规定气体的气流 电解氯化钠和电解熔融氯化钠化学方程式、用途.最好有附带离子方程式. 下列物质放置在空气中,变质原因与其他有本质区别的是 Na NaOH Na2SO3 Na2O2请说明原因 一块金属钠放置在空气当中,发生一系列氧化,最终生成什么? 1.电解NaCl固体熔融物化学方程式---------2.电解饱和食盐水---------3.NaOH溶液与CO2 CO2少量------------ CO2足量---------- Na2O,Na2O2的化学键?分别是什么化学键?离子键?共价键?快 金属钠长期置放在空气中会生成什么? 电解熔融氯化钠和电解饱和食盐水为什么它们的化学方程式 不一样呢?不都是氯化钠嘛? Na2O与Na2O2中化学键的不同点是 在空气中加热金属钠 实验现象 结论 完整的 电解熔融氯化钠时为什么写化学方程式,能不能写离子方程式例如2NaCl=(通电)2Na+Cl2能不能写成2Na+ +2Cl-=(通电)2Na+Cl2 Na2O2计算问题一含C、H、O的物质ag在氧气中充分燃烧后产物被Na2O2吸收,符合通式(CO)m(H2)n的产物还是ag,为什么?那什么时候产物会小于ag?( ⊙o⊙?) 长期存放的亚硫酸钠可能会被部分氧化,现通过实验来测定某无水亚硫酸钠试剂的纯度.实验步骤如下:(1)称量a克样品,置于烧杯中.(2)加入适量蒸馏水,使样品溶解.(3)加入稀盐酸,使溶 电解熔融氯化钠制得金属钠的化学式 Na2O2的阴阳离子分别是什么 实验室有一瓶亚硫酸钠试剂,已经被氧化成硫酸钠.某学生设计如下实验来确定其纯度.BaCL2溶液过量的目的是 食盐水的化学式? Na2O2和Na2O2的阴阳离子个数比相同吗? 实验室有一瓶亚硫酸钠试剂,已经被氧化成硫酸钠.某学生设计如下实验来确定其纯度.已知往溶液里加盐酸发生如下反应2HCL+Na2SO3=2NaCL+SO2↑H2O(1)有以下实验操作步骤,其正确的操作顺序是-----A 请问,电解食盐水,怎样防止石墨电极脱落? Na2O2阴阳离子数之比?是不是1: 验证亚硫酸钠是否变质的试剂根据反映现象判断,未变质,部分变质,全部变质.
备案号:鲁ICP备13029499号-2 说三道四 www.s3d4.cn