你应该了解的Core Image & CIFilter
敲了好长时间才把 CIFilter 大部分的滤镜敲打完毕(就是好奇,也看看效果啥的)。也就是属于一遍敲打一边学习。(因为接触CIFilter的时候没有考虑到主线程的问题,所以都是在drawrect中画的。性能不好,也不想给你们看我敲的东西了,自己看着都觉着写的什么玩意)正好有这个机会,把我的学习经验跟大家分享一下,大家可以少走弯路。大家一起学习 Core Imgae (** 就当是无事了解一下也是好的啊**),走上一条不“归路”……
目录
1.写在"CIFilter"前边关于"Core Image"的基础知识
2.那些你应该知道常用"CIFilter"滤镜
3."CIFilter"中的重要矩阵——"卷积矩阵"
4.在"CIFilter"中的一些小技巧
Core Image 基础知识
#首先 —— 我们要明白,当我们操作 || 改变 Image 的时候,我们其实操作的是DATA数据`
如果我们需要将图片转换为Data数据类型。那么我们可以这样做:
UIImage *tempImage = [UIImage imageNamed:@"test_new"];
CFDataRef imageData = CGDataProviderCopyData(CGImageGetDataProvider(tempImage.CGImage));
#ps:打印这个数据 " <0c71a5ff 0c70a5ff 0d71a5ff 0c71a5ff
0c71a5ff 0c71a5ff 0c71a5ff 0c71a5ff 0c71a5ff 0c71a5ff>"
随便截取一段打印的数据,每一个item代表一个颜色:"R-G-B-A".
了解了这个:"**图片某像素颜色的抓取** && **图片颜色RGBA进行矩阵修改**"那就看起来就容易多了。
#当然你还要注意的就是 UIImage | CGImage | CIImage 之间的区别
其实归结到底,他们只是不同的框架下得产物,同样也正因为不同的框架,使得他们的操作发生了质的变化。
•UIImage : 负责UIKit中的图片展示&数据管理。(CPU计算)
•CGImage: CoreGraphic中对图片的"旋转、缩放 & 挖取"工作。(GPU计算)
•CIImage : 描述一个如何产生一个图像,但其本身本身并不包含图像数据,
它代表的是图像数据或者生成图像数据的流程(如"滤镜的输出")
#Core Image 的优势:
最大化利用其所运行之上的硬件的。每个滤镜实际上的实现,即-"内核",是由一个
GLSL(即 OpenGL 的着色语言) 的子集来书写的.当多个滤镜连接成一个滤镜图表,
Core Image 便把内核串在一起来构建一个可在 GPU 上运行的高效程序
"事实上,图像处理和渲染就是将渲染到窗口的像素点进行许多的浮点运算,"
"那么GPU (图形处理器) 可以高效的完成。"
屏幕快照 2016-10-25 上午10.44.33.pngCore Image 概述
Core Image 是 iOS 5 新加入到 iOS 平台的一个图像处理框架,提供了强大高效的图像处理功能,
用来对基于像素的图像进行操作与分析, 内置了很多强大的滤镜(Filter) (目前数量超过了180种),
这些Filter 提供了各种各样的效果, 并且还可以通过 "滤镜链" 将各种效果的 Filter叠加起来
形成强大的自定义效果。~
IOS8之后更是支持自定义Filter
•自动图像增强技术支持
•链接多个Filter,进行滤镜链
•"iOS8" 增强 GPU 渲染,在后台也能继续使用GPU处理。
•引入 CIDetector,提供一些常用的图片识别功能:人脸识别、条形码识别、文本识别等。
•越来越多的框架结合:OpenGL ES . Metal . SceneKit . SpriteKit
•iOS10 也对Core Image 有更新内容
#足可以看出 "Apple" 对 "Core Image" 的重视
Core Image 使用
**CIFilter 使用起来特别简单 **
CIFilter 基础类
•Core Image: 输入(可通过UIImage、图像文件和像素数据创建)&&输出图像
数据(filter.outputImage方法获得)
•CIFilter: 应用的滤镜,通过键-值对 决定操作参数(可通过"[filter attributes]"查看
参数的取值范围以及说明)
•CIContext: 表明上下文,通过CIContext绘制及渲染的CIImage图片数据,
才会绘制成APP可以使用的图片
我们使用"CIConvolution3X3"举例
- (UIImage *)outputImageWithFilterName:(NSString *)filterName {
// 1. 获取source图片
UIImage *inputOrigin = [UIImage imageNamed:@"histogram"];
// 2. 创建滤镜
CIFilter *filter = [CIFilter filterWithName:filterNamekeysAndValues:kCIInputImageKey, ciImage, nil];
// 设置相关参数
{
CIImage *inputImage = [CIImage imageWithCGImage:inputOrigin.CGImage];
[filter setValue:inputImage forKey:kCIInputImageKey];
CGFloat weights[] = {0,-1,0,
-1,5,-1,
0,-1,0};// 进行打磨处理
# MARK:- 使用卷积5X5矩阵的话, 这个可以实现重影效果"(3X3也可以,效果不好看)"
// CGFloat weights[] = {0.5,0,0,0,0,
// 0,0,0,0,0,
// 0,0,0,0,0,
// 0,0,0,0,0,
// 0,0,0,0,0.5};//重影效果
CIVector *inputWeights = [CIVector vectorWithValues:weights count:9];// count 必须与输入的一致
[filter setValue:inputWeights forKey:kCIInputWeightsKey];
[filter setValue:@0 forKey:kCIInputBiasKey];
}
// 3. 渲染并输出
CIImage CIImage *outputImage = [self.filter outputImage];
// 4. 获取绘制上下文
self.context = [CIContext contextWithOptions:nil];
// 5. 创建输出
CGImage CGImageRef cgImage = [self.context createCGImage:outputImage fromRect:[outputImage extent]];
UIImage *image = [UIImage imageWithCGImage:cgImage];
// 6. 释放
CGImage CGImageRelease(cgImage);
return image;
}
#输入参数: inputImage . inputWeights . inputBias
# ps: CIConvolution7X7 . CIConvolution9Horizontal . CIConvolution9Vertical
# "这里就涉及到卷积矩阵了。"
效果如下:
屏幕快照 2016-10-25 下午3.32.56.png常用的CIFilter
#CIConstantColorGenerator("生成纯色图片做背景用") | CICrop ("裁切图片") |
#CISourceAtopCompositing("两张图进行合成-前景&背景")| CIQRCodeGenerator("二维码生成")
# CIGaussianBlur ("高斯模糊")| CIConvolution3X3 ("自定义卷积Kernel")
#CICheckerboardGenerator("棋盘样式") | CIStripesGenerator("格子布")
# CIColorCrossPolynomial("多项式交叉"这个比较麻烦。参数设置需要计算等等,但是可以很强大)
多项式交叉
CIColorCrossPolynomial多项式计算规则
多项式交叉能做到的效果
卷积矩阵(让我们离真相更加接近)
网上的介绍:每个Filter被称为Kernel 内核,一部分的核心指的就是这个 卷积矩阵 。
#这里其实发生了:
过滤器连续地读,从左至右,从上到下,内核动作区域的所有像素。
它通过相应的价值和增值结果内核乘以他们每个人的价值。
初始像素已经成为42:
(40*0)+(42*1)+(46*0)+(46*0)+(50*0)+(55*0)+(52*0)+(56*0)+(58*0)= 42
过滤器会进行copy图片,在副本上进行工作得出图形结果("作为初始像素向下移动一个像素")
#这个卷积矩阵可以实现多种效果:
锐化 | 模糊 | 边缘检测 | 浮雕 ……
屏幕快照 2016-10-25 下午3.24.43.png
一些你应该知道的小知识
# MARK:
1.UIImage 属性.CIImage 可能为nil。
ps:只有UIImage基于CIImage创建的,才能通过.CIImage得到 <CIImage>
2.使用filter生成的图片并不是总能使用UIImage进行渲染
ps:生成的图片.extent 可能会是 "infinite(无穷大)".这样的图片不会被渲染,
需要进行CICrop进行裁切。
3.如果filter对图片进行放大等操作而且需要裁切的,那么他是通过"Center向四周放大的"
那么或许图片的时候应该考虑到#裁切的范围补偿。
CIContext GPU & CPU 对我们处理图片的影响
在创建结果 UIImage 的时候,最简单的方式就是通过 imageWithCIImage 来实现。这种情况下,不需要显示的声明CIContext,因为 imageWithCIImage 内部自动完成了这个步骤。这使得使用 Core Image 更加的方便。当然,它也引起了另外一个问题,每次都会重新创建一个 CIContext,然而 CIContext 的代价是非常高的。
并且,CIContext 和 CIImage 对象是不可变的,在线程之间共享这些对象是安全的。所以多个线程可以使用同一个 GPU 或者 CPU CIContext 对象来渲染 CIImage 对象。
所以重用 CIContext 是很有必要的。这意味着,我们不应该使用 imageWithCIImage 来生成 UIImage,而应该自己创建维护 CIContext。
#建议频繁操作CIContext。可以建一个全局的变量去维护。(每个上下文中都是有缓存的,频繁创建就用不到 上下文中 的缓存,既浪费资源又浪费内存的消耗)
基于 GPU 的话,处理速度更快,因为利用了 GPU 硬件的并行优势。可以使用 OpenGLES 或者 Metal 来渲染图像,这种方式CPU完全没有负担,应用程序的运行循环不会受到图像渲染的影响。
但是 GPU 受限于硬件纹理尺寸,而且如果你的程序在后台继续处理和保存图片的话,那么需要使用 CPU,因为当 App 切换到后台状态时 GPU 处理会被打断。使用 CPU 渲染的 iOS 会采用 GCD 来对图像进行渲染,这保证了 CPU 渲染在大部分情况下更可靠,比 GPU 渲染更容易使用,可以在后台实现渲染过程。
综上,对于复杂的图像滤镜使用 GPU 更好,但是如果在处理视频并保存文件,或保存照片到照片库中时,为避免程序进入后台对图片保存造成影响,这时应该使用 CPU 进行渲染。
创建CIContext
// 创建基于 CPU 的 CIContext 对象 (默认是基于 GPU,CPU 需要额外设置参数)
context = [CIContext contextWithOptions: [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:kCIContextUseSoftwareRenderer]];
// 创建基于 GPU 的 CIContext 对象
context = [CIContext contextWithOptions: nil];
// 创建基于 GPU 的 CIContext 对象
EAGLContext *glcontext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
context = [CIContext contextWithEAGLContext: glcontext];
需要特别注意:
"contextWithOptions"方法 创建的 "context"并没有实时性能, 虽然渲染是在 "GPU" 上执行,
但是其输出的 "image" 是不能显示的,只有当其被复制回 "CPU" 存储器上时,才会被转成一个可被
显示的 "image" 类型,比如 UIImage。
基于GPUImage库的计算。 以<CISepiaTone> - ** 模拟器的状态下**为例:
# CPU 耗时:"83.47 ms" —— "( 自己手动计算图片每个像素目标值 ,GPU进行绘制图片)"
# Core Image 耗时: "1217.52 ms" —— "( 用CIFilter计算,生成CIImage对象进行绘制 )"
# GPUImage 耗时: "340.92 ms" —— "使用GPUImage库进行计算,GPU进行绘制图片"
ps:以上信息为单次计算,可能会有一些误差在里边。大体的时间比例是正确的
在这里不得不提醒大家一下:
通过上边的数据显示,说明:**Core Image** 生成图片是特别占用cpu的。
所以当我们进行 CIFilter 生成 UIimage 的时候,尽量不要放到主线程中操作。
当计算这个任务被加入主线程中,主线程是一个串行的队列,每个操作都会阻碍"主线程屏幕的刷新"
#ps: 这个会造成卡顿的现象的。
#(顺带着该学习一下多线程了,小编这几天刚看完多线程。又准备去看动画去了推荐"UIDynamic")
# UIKit中的 "动力学引擎" -- 比较Apple原生的东西,看到效果还不错的。这要是都让咱自己写啊,怎么会有精力呢!
# 苹果的东西还是值得一学的。"妈妈再也不用担心我的学习了。"
可能CIFilter内容太多不容易记住:
获取CIFilter-Names : [CIFilter filterNamesInCategory:nil]
获取当前Filter的输入参 : [filter inputKeys]
获取当前Filter的输出参数 : [filter outputKeys]
输入参数的attributes : [filter attributes]
那那那,小编就学会这点东西。有啥书写有误的东西,欢迎指教!
最后啊,小编还是想多努力学习,Core Image 仅仅是性能不出众而已。但我们依旧要热爱它,因为apple自家的东西。我们都要支持----(ios开发工作者)
可是话说回来,不是还有 人脸识别 值得你学习吧。
IOS10 图库 可是加入了 ** 人物 ** 的功能呢 。
苹果软件工程高级副总裁克雷格·费德里奇在演讲中表示,“先进计算机视觉”(Advanced Computer Vision)
是今年照片应用最大幅度的一次更新,因为苹果通过深度学习技术将人脸识别带到了 iPhone 身上。