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

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

百度开源平台上线,聚合百度开源项目 盘点TOP500:值得关注的超算,及当下趋势 【BDTC讲师】Tachyon作者:大数据存储以及处理框架经验分享 进一步称霸中国:低端设备让Android在中国每季获3%增长 低端设备撑起Windows Phone市场份额 研发周报:你的数据库准备好过冬了吗 JVM垃圾收集器使用调查:CMS最受欢迎 技术创业不能一味追求“骨感”,必要时丰富自己的5个途径 帷千动媒副总经理兰旭:整合现在,梳理未来! 11月份浏览器份额:IE继续上涨,Chrome仍不温不火 Windows 8令人担忧:8和8.1两版本份额目前仅有9.3% 一周消息树:微软还需更激进的手段——开放Windows Phone 【开源推荐】Genome.js:当DNA遇到开源 Go 1.2发布 着重语言特性的改进 微软资深IE专家邹颂兵:好产品才是竞争的关键 Web应用程序完全测试指南 Python正在取代R,成为数据科学界新宠 代号Threshold:微软将推Windows统一平台Threshold 日本任天堂掌机应用:《卢浮宫》革了谁的命? [TUP第31期]《浪潮之巅》吴军:硅谷3.0助力中国企业走向国际 SequoiaDB创始人:比MongoDB领先一到两年 打造企业级NoSQL数据库 [对话CTO]甲骨文熊光樑:全球研发模式开发出接地气产品 GitHub中国游记之长城——跨越那堵看不见的墙 IE11开发人员工具:UI响应工具详解 2013 Linux领域年终盘点 腾讯云俱乐部深圳站成功落幕 开创移动开发新篇章 解读云计算、大数据、物联网等九大IT技术发展趋势 苹果已证实收购Topsy或将涉足社交领域 触摸未来:Tactus微流体技术2014年来袭 Windows的未来:一个核心 多个版本 Github项目中使用率最高的Java/Ruby/JS库 在页面上显示书名和图书简介两个字段的内容的问题:前者正常显示,而后者显示出现乱码?真奇怪!求助!谢谢! ADO的游标是什么意思? JB7和weblogic 7.0 配置 EntityBean的问题,有异常? 写了个程序用来修改SyGate的数据库,谁有兴趣? 初次使用mysql 关于服务器的用户全部被人删除 真的很是问题 如何保留rtf的文本格式啊? 哪有免费论坛程序? GetFieldValue( nIndex, varValue, nFieldType )函数出错 请问Updata和Refresh有什么区别? DBNull问题,高手指教! 怎么样用xml做树形目录菜单,如csdn的左边的目录菜单,up者有分 关于菜单项的问题 是用outlook到如数据的问题 test7777 求救!!!!! 随机从表中抽出N条记如何写? 如何用脚本动态的生成一个新网页? 如何做出象DELPHI中的菜单在ControlBar1中的样子? 急·!!怎样能把磁盘上的文件删出一行 有关多字段排序的问题? 什么是发布与订阅? 1、五一节快到了,大家打算怎么过啊?:P 我从网上Down下一个VB的事例,但是窗体上控件的位置没法移动??? 如何在访问不同域的COM+服务,如何配置? 求购CRM源码(delphi) 我写了一个exif读取的程序,欢迎大家热心测试,给出好的建议的赠送代码 2、五一散分帖,收集一些东东。 问个弱弱的问题! 帮忙了,谁有XP的序列号? 一个很菜的问题,求助!!! 超时已过期错误提示问题 河北保定,转让大量C++世界经典。 关于控件堆叠的问题 session的问题 今天发工资,太少不爽,大散分,谁要是能帮我找一个挣钱的私活,我给他200分(令给) 请教数据库! 请教有关对话框的问题? 3.五一散分帖,我一个朋友说。。。。。。。。 高分相求:JBUILDER8 Enterprise 版,或下载地址。 怎么才能获得editbox的值 请问rasWinGod 这个控件如何用!(在线等待) 请问如何用CB生成可以在集成到网页上的activeX控件?急阿........ 如何把用逗号隔开的字符串赋给一个数组? FileView下的External Dependencies里面的.h文件是什么?! 请问如何在数据窗口中显示记录序号 怎么看自动生成的Makefile到底做了什么?紧急总动员,满分,在线等待 回答我问题 今天打开邮箱,竟然没有lj邮件,感动ing,散分ing 4、五一散分帖,问问题。:) 关于爱因思坦相对论记得爱因思坦对时间有所结论,以前知道,现在忘了,就是当什么达到一个程度时,时间便停止.当什么达到一个程度是,时间便倒流.当什么法到一个程度时,时间便加快.我觉得 “一座座青山紧相连,一片片白云绕山间······谁不说俺家乡好······”很多同学一定听过这首优美的歌曲,家乡的一草一木都那么让人眷恋.结合生物多样性的知实写一篇300字的短文 什么是农村劳动密集型产业 将洁净的铁钉放入稀盐酸会有什么现象 大肠杆菌培养时要核酸吗? 运用生物多样性知识为家乡写一篇短文 试述锻造用高速钢坯加热操作的要点. 电泳时,为什么要盖上盖子 铝挤型散热器,阳极与电泳哪个散热更好? 将铁片加到1L0.5Mol/LFeCl3溶液中,当Fe2+和Fe3+的浓度相等时,贴片的质量减少多少? 从大肠杆菌细胞中提取到的核酸彻底水解,至形成不能再水解的小分子,则小分子种类 显卡散热器能降低多少温度我的是5770,玩孤岛危机开高特效温度能上90甚至更高,加个散热能降到多少,就算温度低一直开高特效对显卡有害不 同学们,你的暑假生活一定过得非常有意思吧?选一件你觉得特别有趣或有意义的写下来.别忘 醋为什么要盖盖子如题,是醋会挥发还是水会挥发? 结合所学生物多样性的只是写一篇不少于400字的短文 要写提纲哦 急!(1)将铁片加入到1L0.5mol/LFeCl3溶液中,当溶液中Fe3+和Fe2+的浓度相等时,铁片质量减小( )A.5.6克 B.11.2克 C.2.8克 D.1.4克 (2)9、向某晶体的水溶液中加入含Fe2+的溶液后 二氧化碳激光和氦氖激光有什么不同?它们所发出的热量一样吗? 狭义相对论和广义相对论有什么区别? 在相同温度下,胆矾和SO3,哪种物质溶解度高 氦氖激光气是纯净物吗?这是我们化学卷上的一道题.也许是我孤陋寡闻,不知道氦氖激光气是什么东西, 电泳后漆膜气泡是为什么?怎么处理? 将足量铁片加到1L0.5mol/LFeCl3溶液中,当Fe2+,Fe3+的浓度相等时铁片质量减少多少 氦氖激光照射要多久 磁铁矿有500t,含Fe3O4 70% 能炼多少铁 较低轨道是指椭圆轨道还是指圆轨道? 爱因思坦的智商多高 put one's mind to 在地球的圆形同步轨道上有某一卫星正在运行,则下列说法正确的是( ) A.卫星的重力小于在地球表面时受到的重力 B.卫星处于完全失重状态,所受重力为零 C.卫星离地面的高度是一个定 画图的时候将坐标系显示出来但是并没有看到坐标系的图标,请问solidworks有默认的坐标系吗 做了个雨棚,玻璃准备用1.9M*1.4M共6块,6+6的夹胶钢化玻璃,还有这么大的玻璃大概有多重?几个人能搬的动?因为要搬到屋顶上 从30cm长的木条上截出两段长度相等的木条后,还剩6cm长的木条,求截去的每一段木条的长是多少cm?设未知数,解方程, 所有的名言要短的是有关只要名言就行 与转动惯量有关的1道物理题一长为L,质量为m的匀质细棒,平放在粗糙的水平桌面上.设细棒与桌面的摩擦系数为μ,令细棒最初以角速度ω绕通过端点且垂直细棒的光滑轴O转动,则它停止转动前需 一根木条长28米,用去12米.用去的部分占这根木条长度的几分之几 全部的名人名言谚语、诗句都可以,越多越好, 一个关于杆的转动惯量的问题在以长杆的一端为轴旋转时所得转动惯量为ml^2/3,将l 缩短一半得转动惯量为ml^2/12,而以杆的中点为轴转动惯量为ml^2/12,也就是说,在轴的另一边增加l/2的长度,效果 求过点A(5,2)在两坐标轴上的截距互为相反数的直线l的方程求出来我会加分的 各类名言警句多一点警句 找一篇有关保护生物多样性的论文 蛋白质复性和核酸复性区别 各类名人名言越多越好! NO matter what you do,you should put your____into it.是填heart还是mind,答案为什么是mind? 核酸复性和杂交的区别? 琼脂糖凝胶电泳时上样孔有气泡对电泳结果有什么影响 我国烟草制造业分布在哪里?有哪几个主要的烟草制造区?以及分布在那里的原因? 电子层的能量电子层有能量高低吗?如果有,那是由什么决定的? 人血白蛋白怎么保存 儿童出生率怎么算我乡有22866人口,今年出生280人,出生率是百分之几 电子层能量的能量形式是光?是热?还是?我觉得书本的K,L,M,N……能量依次增大太笼统了吧,根据能量守恒定律,电子的能量是守恒的,所以算能量的话,不理它是何种形式,各层能量应是相等的 实验试剂能否与食品添加剂混放? 生物多样性对我们人类有哪些意义?根据你的看法,写一篇200字的小文章 尺寸(cm):90×60×70.5 这个箱子的体积是多少?(得数保留整立方分米.) 实验得到的多肽可用什么试剂检验,原因是化合物中含有的什么与该试剂发生了颜色反应 22.4LCO与N2混合气体中所含电子数?气体还能求电子数? 大肠杆菌中核酸的含量 你还知道哪些人为维护祖国领土完整作出过贡献,说说他们的事迹. I put my anchor into your 关于爱因思坦的英文介绍~要很短的哦 solidworks中不同零件的输出坐标系一样吗 浙江省的劳动密集型产业有哪些 羊城晚报报业集团将派工作组调查整顿新强风暴袭击欧洲多国 致海陆空交通全部天津召开纪念毛泽东同志诞辰120周年日本外相拟11月出访伊朗 推动伊核问十八届三中全会将于11月9日至12日周恩来诞辰115周年 入党履历表手书消息称人社部正组织研究延迟退休 尚无原山东大学校长任中央综治委办公室专职早恋小情人偷尝禁果 1男孩被判强奸坐日本明仁天皇夫妇将首次访印 前首相森泰国代孕黑市剥削孕母 酬劳低至5.8韩国有望于2015年实现医生对患者远中国3名实习生因多次伪造在留卡 在日日本明仁天皇夫妇将首次访印 前首相森学生用400年前地图合成3D游戏 重强风暴袭击欧洲多国 致海陆空交通全部尼泊尔大选首次准许“第三性”公民拥有网友质疑延迟退休因养老金缺口 南京人索马里政府称无人机击毙“青年党”高级韩国有望于2015年实现医生对患者远法国女婴在后备箱被发现 躺在排泄物中铁杆粉丝“百发百中”20万李东生:收购汤姆逊战略没有错财富大讲坛下期预告价值高过“根宝模式”不是解决之道科比失绝杀献26+5+5+5 湖人惜以法治理想守护和推动司法体制改革沙特的梦魇日之泉西迁尘埃落定歌声中放飞晚年“青春”习仲勋:偷渡,是人民内部矛盾印尼政府倡导“家常菜”WDS广州大奖赛最热动漫品牌过半在广东金逸影视IPO审核已经取消动员社会力量参与禁毒斗争红烧铁锁细数盆菜真味“佛京战”问题主裁遭重罚百名文艺志愿者走进广州最北山村剑走偏锋辣锅香
备案号:鲁ICP备13029499号-2 说三道四 www.s3d4.cn 说三道四技术文摘