iOS8 Core Image In Swift:自动改善图像以及内置滤镜的使用
iOS8 Core Image In Swift:自动改善图像以及内置滤镜的使用
iOS8 Core Image In Swift:更复杂的滤镜
iOS8 Core Image In Swift:人脸检测以及马赛克
iOS8 Core Image In Swift:视频实时滤镜
Core Image是一个很强大的框架。它可以让你简单地应用各种滤镜来处理图像,比如修改鲜艳程度, 色泽, 或者曝光。 它利用GPU(或者CPU)来非常快速、甚至实时地处理图像数据和视频的帧。并且隐藏了底层图形处理的所有细节,通过提供的API就能简单的使用了,无须 关心OpenGL或者OpenGL ES是如何充分利用GPU的能力的,也不需要你知道GCD在其中发挥了怎样的作用,Core Image处理了全部的细节。
Core Image框架给我们提供了这些东西:
- 内置的图片滤镜
- 特征检测能力(如人脸识别)
- 支持自动改善图像
- 能利用多个滤镜组合成一个自定义滤镜
自动改善图像
先 上一个简单的例子。用Single View Application的工程模板建立一个工程,这个工程建好后只有一个AppDelegate和一个ViewController,另外还有一个 Main.storyboard,在Main.storyboard里已经准备好一个ViewController了,我们在这个 ViewController里放置一个UIImageView,调整其frame:
除此之外,因为UIImageView是默认拉伸图片的,我们不想让它变形,把它的ContentMode设置为Aspect Fit。顺便把Auto Layout和Size Classes关掉。
最后在拖两个按钮进来,一个用于显示原图,一个用于自动改善图像,整个ViewController看起来像这样:
接下来在ViewController中增加对应的IBAction方法以及IBOutlet属性:
class ViewController: UIViewController {
@IBOutlet var imageView: UIImageView!
lazy var originalImage: UIImage = {
return UIImage(named: "Image")
}()
......
一个连接到Storyboard的imageView,还有一个只懒加载一次的originalImage属性,这个属性在后面会用到很多次,这里有我整个工程用到的image。
然后在ViewDidLoad里像这样:
override func viewDidLoad() {
super.viewDidLoad()
self.imageView.layer.shadowOpacity = 0.8
self.imageView.layer.shadowColor = UIColor.blackColor().CGColor
self.imageView.layer.shadowOffset = CGSize(width: 1, height: 1)
self.imageView.image = originalImage
}
只做了两件事:一是给imageView加上了阴影边框,只是为了好看;二是把originalImage赋值给imageView。
一行代码显示原图:
@IBAction func showOriginalImage() {
self.imageView.image = originalImage
}
下面是自动改善的代码,我先贴出来,再慢慢说,有一个直观的效果会更有兴趣一些:
@IBAction func autoAdjust() {
var inputImage = CIImage(image: originalImage)
let filters = inputImage.autoAdjustmentFilters() as [CIFilter]
for filter: CIFilter in filters {
filter.setValue(inputImage, forKey: kCIInputImageKey)
inputImage = filter.outputImage
}
self.imageView.image = UIImage(CIImage: inputImage)
}
把IBAction和IBOutlet连接对之后,运行起来应该就能看到以下效果了:
点击自动改善就能看到效果了,可能运行会有点慢,因为我们还没做优化,如果觉得改善效果不明显的话,可以多点击几次原图来对比一下。
虽然有些问题,但是已经不妨碍我们继续探索了。上面的自动改善代码显式地用到了两个类(我为什么在这里要用显式这个词?):CIImage和CIFilter,其中:
- CIImage:这是一个模型对象,它保存能构建图像的数据,可以是图像的Data,可以是一个文件,也可以是CIFilter输出的对象。
- CIFilter:滤镜,不同的CIFilter实例能表示不同的滤镜效果,不同的滤镜所能设置的参数也不尽相同,但它至少需要一个输入参数以及能生成一个输出对象。
另外Core Image的自动改善功能能智能的对图像的柱状图(histogram?)、人脸区域以及元数据进行分析,只需要传入一个Image作为输入参数,就能得到一组能使图像改善的滤镜。
- 图片的方向,这对CIRedEyeCorrection、CIFaceBalance等滤镜来说格外重要,因为Core Image需要精确的对面部进行检测。
- 是否只需要消除红眼(设置kCIImageAutoAdjustEnhance为false)。
- 是否使用除了消除红眼以外的所有的滤镜(设置kCIImageAutoAdjustRedEye为false)。
- NSDictionary *options = @{ CIDetectorImageOrientation :
- [[image properties] valueForKey:kCGImagePropertyOrientation] };
- NSArray *adjustments = [myImage autoAdjustmentFiltersWithOptions:options];
在这个例子中,我就不传入Option字典了,因为不涉及图片方向的问题。
- CIRedEyeCorrection:修复因相机的闪光灯导致的各种红眼
- CIFaceBalance:调整肤色
- CIVibrance:在不影响肤色的情况下,改善图像的饱和度
- CIToneCurve:改善图像的对比度
- CIHighlightShadowAdjust:改善阴影细节
for filter: CIFilter in filters {
let inputKeys = filter.inputKeys()
print(filter.name())
println(inputKeys)
...
打印结果:
- CIFaceBalance[inputImage, inputOrigI, inputOrigQ, inputStrength, inputWarmth]
- CIVibrance[inputImage, inputAmount]
- CIToneCurve[inputImage, inputPoint0, inputPoint1, inputPoint2, inputPoint3, inputPoint4]
- CIHighlightShadowAdjust[inputImage, inputRadius, inputShadowAmount, inputHighlightAmount]
几乎所有的滤镜都有inputImage这个输入参数,我们可以直接用系统预置的各种key来设置参数(如kCIInputImageKey),系统已经预置了大部分常用的key,如果你发现有的key系统没有预置,你可以直接使用获取的key名的字符串来作key,如:
filter.setValue(inputImage, forKey: kCIInputImageKey)
//两者设置方式完全一样
filter.setValue(inputImage, forKey: "inputImage")
对自动改善图像功能来说,我们不需要知道太多的细节,设置inputImage就可以了。
接下来填坑。
上面的代码有两个问题:一是在每次使用自动改善的过程中感觉到明显的慢;二是图像在自动改善后变形了。原图和改善后的图像对比:
我把UIImageView的contentMode设置为Aspect Fit,就是不希望图片发生变形,而是按等比例缩放,如果把UIImageView的背景色设置为红色的话,在显示原图的时候可以看到上下均有红色,而改善之后的图片就没有红色。由于苹果表示UIImage是完全支持CIImage的,所以文档中并没有指出出现这个问题的原因,我参考了下面这个贴子:
上面有说通过UIImage(CIImage:)方法得到的UIImage并不是一个基于CGImage的标准UIImage,所以不能按一般的显示规则去理解,因此我们要换种方式去得到一个真正的UIImage,解决方法放在下面再说。
在 之前介绍CIImage和CIFilter的时候我们用到显式这个词,因为在代码里可以直观的看到使用了这两个类,CIImage提供图像的信 息,CIFilter提供滤镜,当我们调用CIFilter的outputImage方法时,此时Core Image并不会去渲染图像,而是通过计算各种参数,并把计算结果存储到CIImage对象中,只有当真正将要显示的时候,才会通过第三个对象去渲染。这 个对象就是CIContext。
CIContext是Core Image处理图像的关键,它和Core Graphics的CGContext类似但又与之不同,CIContext可以被重用,不必每次都新建一个,同时在输出CIImage的时候又必须有一个,简而言之,Core Image通过CIContext来渲染CIFilter产生的对象。
在 上面的例子中我们没有使用CIContext,但在调用UIImage(CIImage:)的时候Core Image隐式地在内部使用了CIContext,也就是把我们需要手动做的工作自动地完成了。但是这就有了一个问题,在每次调用 UIImage(CIImage:)的时候它都会重新创建一个CIContext对象,这在用完即毁的情况下不会造成很大的影响,但在反复地使用滤镜的过 程中就很影响性能了,为了防止这种情况,我们把CIContext对象重用起来,让ViewController持有一个懒加载的属性:
lazy var context: CIContext = {
return CIContext(options: nil)
}()
CIContext 在初始化的时候需要一个字典,可以通过kCIContextUseSoftwareRenderer创建一个基于CPU的CIContext对象,默认是 创建基于GPU的CIContext对象,不同之处在于GPU的CIContext对象处理起来会更快,而基于CPU的CIContext对象除了支持更 大的图像以外,还能在后台处理。我们传nil创建基于GPU的CIContext对象就可以了。
有了可重用的CIContext对象,在创建UIImage的时候需要这样:
@IBAction func autoAdjust() {
var inputImage = CIImage(image: originalImage)
let filters = inputImage.autoAdjustmentFilters() as [CIFilter]
for filter: CIFilter in filters {
filter.setValue(inputImage, forKey: kCIInputImageKey)
inputImage = filter.outputImage
}
//self.imageView.image = UIImage(CIImage: inputImage)
let cgImage = context.createCGImage(inputImage, fromRect: inputImage.extent())
self.imageView.image = UIImage(CGImage: cgImage)
}
虽 然在第一次执行自动改善的时候会有点慢(因为要创建CIContext对象),但是在反复执行的情况下性能改善了很多,而且这样一来还解决了第二个问题, 即ContentMode的问题。如果没有特殊情况,应该总是用这种方式创建一个CGImage,再把CGImage转成UIImage。
使用各种内置滤镜
func showFiltersInConsole() {
let filterNames = CIFilter.filterNamesInCategory(kCICategoryBuiltIn)
println(filterNames.count)
println(filterNames)
for filterName in filterNames {
let filter = CIFilter(name: filterName as String)
let attributes = filter.attributes()
println(attributes)
}
}
在这个方法里传入的类别参数是kCICategoryBuiltIn,表示会输出iOS8 Core Image的所有滤镜:
class ViewController: UIViewController {
@IBOutlet var imageView: UIImageView!
lazy var originalImage: UIImage = {
return UIImage(named: "Image")
}()
lazy var context: CIContext = {
return CIContext(options: nil)
}()
var filter: CIFilter!
......
// MARK: - 怀旧
@IBAction func photoEffectInstant() {
filter = CIFilter(name: "CIPhotoEffectInstant")
outputImage()
}
// MARK: - 黑白
@IBAction func photoEffectNoir() {
filter = CIFilter(name: "CIPhotoEffectNoir")
outputImage()
}
// MARK: - 色调
@IBAction func photoEffectTonal() {
filter = CIFilter(name: "CIPhotoEffectTonal")
outputImage()
}
// MARK: - 岁月
@IBAction func photoEffectTransfer() {
filter = CIFilter(name: "CIPhotoEffectTransfer")
outputImage()
}
// MARK: - 单色
@IBAction func photoEffectMono() {
filter = CIFilter(name: "CIPhotoEffectMono")
outputImage()
}
// MARK: - 褪色
@IBAction func photoEffectFade() {
filter = CIFilter(name: "CIPhotoEffectFade")
outputImage()
}
// MARK: - 冲印
@IBAction func photoEffectProcess() {
filter = CIFilter(name: "CIPhotoEffectProcess")
outputImage()
}
// MARK: - 铬黄
@IBAction func photoEffectChrome() {
filter = CIFilter(name: "CIPhotoEffectChrome")
outputImage()
}
func outputImage() {
println(filter)
let inputImage = CIImage(image: originalImage)
filter.setValue(inputImage, forKey: kCIInputImageKey)
let outputImage = filter.outputImage
let cgImage = context.createCGImage(outputImage, fromRect: outputImage.extent())
self.imageView.image = UIImage(CGImage: cgImage)
}
这些都写好后,在UI上把各种按钮及touch事件绑定好,UI看起来像这样:
运行后各种滤镜效果:
以上就是对Core Image内置滤镜的简单使用,如果你不需要对滤镜做更加细粒度控制的话,上述方法就够用了。
GitHub下载地址
UPDATED:
参考资料:
iOS8 Core Image In Swift:自动改善图像以及内置滤镜的使用的更多相关文章
- iOS8 Core Image In Swift:人脸检测以及马赛克
iOS8 Core Image In Swift:自动改善图像以及内置滤镜的使用 iOS8 Core Image In Swift:更复杂的滤镜 iOS8 Core Image In Swift:人脸 ...
- iOS8 Core Image In Swift:更复杂的滤镜
iOS8 Core Image In Swift:自动改善图像以及内置滤镜的使用 iOS8 Core Image In Swift:更复杂的滤镜 iOS8 Core Image In Swift:人脸 ...
- iOS8 Core Image In Swift:视频实时滤镜
iOS8 Core Image In Swift:自己主动改善图像以及内置滤镜的使用 iOS8 Core Image In Swift:更复杂的滤镜 iOS8 Core Image In Swift: ...
- NET Core 3.0 新姿势 将AutoFac替换内置DI
.NET Core 3.0 和 以往版本不同,替换AutoFac服务的方式有了一定的变化,在尝试着升级项目的时候出现了一些问题. 原来在NET Core 2.1时候,AutoFac返回一个 IServ ...
- Swift - 解析JSON数据(内置NSJSONSerialization与第三方JSONKit)
一,使用自带的NSJSONSerialization 苹果从IOS5.0后推出了SDK自带的JSON解决方案NSJSONSerialization,这是一个非常好用的JSON生成和解析工具,效率也比其 ...
- swift 4 生成随机数的内置方法汇总
第一种是drand48(),不接收参数, 返回的类型是Double. 就返回 0到1之间的Double类型的随机数.举个例子: //每次点击button,button 的颜色会随机变换. class ...
- Windows Azure 自动伸缩已内置
WindowsAzure平台提供的主要优点之一是能够在有需要时快速缩放云中的应用程序以响应波动.去年7月以前,您必须编写自定义脚本或使用其他工具(如Wasabi或MetricsHub)来启用自动 ...
- 【温故而知新-Javascript】图片效果(图像震动效果、闪烁效果、自动切换图像)
1.当鼠标指针经过图像时图像震动效果 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" " ...
- 如何为 .NET Core CLI 启用 TAB 自动补全功能
如何为 .NET Core CLI 启用 TAB 自动补全功能 Intro 在 Linux 下经常可以发现有些目录/文件名,以及有些工具可以命令输入几个字母之后按 TAB 自动补全,最近发现其实 do ...
随机推荐
- iOS平台下cookie的使用
iOS平台下cookie的使用 首先,先介绍下iOS对cookie的操作的两个类: 帖子来源于:http://blog.csdn.net/chun799/article/details/1720690 ...
- 伸缩放大的js
window.onload = function() { var div1 = document.getElementById('div1'); div1.onmous ...
- 《第一行代码》学习笔记14-UI(3)
1. (1)所有控件都是直接或间接继承自View,所用的所有布局都是直接或间接继承自ViewGroup的. (2)View是Android中一种最基本的UI组件,可以在屏幕上绘制一块矩形区域,并能响应 ...
- android 5.0 受欢迎的API简介
android 5.0 作为系统的一次重大升级,给用户和开发者带来了全新的体验.Material Design不但在视觉和操作上更胜一筹,扩展UI工具包同时也引入了大量新的API. 1. 3D视图和实 ...
- VC连接数据库方式
转自:http://www.cnblogs.com/renyuan/archive/2012/07/27/2612412.html 目前Windows系统上常见的数据库接口包括: ODBC(开放数据库 ...
- mysql to sql sersver
USE SCK_PARA GO /****** Object: StoredProcedure [dbo].[syncdata_mysql2sqlserver] Script Date: 08 ...
- PHPexcel 判断日期类型
若已经确定某列为日期型数据: for($currentRow=2;$currentRow <= $allRow;$currentRow++){ //从哪列开始,A表示第一列 for($curre ...
- Java学习笔记--多线程
rollenholt的博文:http://www.cnblogs.com/rollenholt/archive/2011/08/28/2156357.html 弹球例子: 0. 创建Bounce框架 ...
- ListView 实现分组
1:FragmentHack4.java /** * Created by y on 15-1-2. */ public class FragmentHack4 extends Fragment{ V ...
- 设置Ubuntu Mysql可以远程链接
1:修改my.cnf配置文件 $sudo vim /etc/mysql/my.cnf 修改为: bind-address = 0.0.0.0 2:进行授权操作 mysql> grant all ...