写点什么

Core Image:iOS 图像处理技术追踪

  • 2020-08-09
  • 本文字数:5091 字

    阅读完需:约 17 分钟

Core Image:iOS图像处理技术追踪

Core Image 是苹果官方提供的图像处理框架,通过丰富的 built-in(内置)或自定义 Filter(过滤器)高效处理静态图片、动态图片或视频。开发者还可以通过构造 Filter 链或自定义 Core Image Kernel 来实现更丰富的效果。

在 WWDC20 中,苹果官方针对 Core Image 技术在以下三方面做了优化:Core Image 对视频/动图的支持、基于 Metal 构建 Core Image (CI) Kernel 以及 Core Image 的 Debug 支持。

这三方面会在下文逐一提到,文末笔者也会浅谈 Core Image 在手淘图片库中的应用可能以及对 Core Image 技术的展望。

优化 Core Image 对视频/动图的支持

创建 CIContext

创建 CIContext 时,需要遵循一个 view 一个 context 的原则。由于视频的每一帧都会发生变化,将 CIContext 的 cacheIntermediates 属性设置为 false 可以大大减少内存消耗。


如果在使用 Core Image 时将同时运用 Metal(作为输入或输出),通过设置 MTLCommandQueue 属性创建 CIContext 将会是较好选择。在不使用 MTLCommandQueue 的情况下,每一个 Metal 或 CoreImage 执行的任务都在不同队列中并以 wait 命令分隔开,导致任务执行效率低。通过设置 MTLCommandQueue 创建的 CIContext 和相应的 Metal 任务在同一队列中,能提高 app 的运行效率。



图一:不使用 MTLCommandQueue 的工作流程



图二:使用 MTLCommandQueue 的工作流程

编写 Core Image Kernel(在 Metal 中实现)

为了将效果处理得更丰富,通过 Metal 来实现自定义 CI Kernel 是个高效的选择。苹果官方提供了的许多方便部署的内置工具(都通过 Metal 实现),如内置 CI 滤镜。通过 Metal 实现自定义 CI Kernel,不仅 app 的 runtime 编译时间将会大大减少(这段工作会移至 app 构建完成后进行),开发者还能获得高性能语言特性(如 gather-reads、group-writes、半精度浮点数)、高效开发体验(如缩进检查、缩进高光)等功能。

选择合适的 View 类

如果要对视频/动图应用特效,静态内容 View 如 UIImageView 或 NSImageView 应当被避免。AVPlayerView 和 MetalKit View(MTKView)是个两个不错的选择。前者为简单选择,后者为进阶选择。


使用 AVPlayerView 时,需要创建 AVMutableVideoComposition 对象,CI 滤镜在 block 中执行图像处理任务。在进行断点 debug 时,通过点击 CIImage 对象地址右侧的眼睛图示可以浏览 CI 滤镜处理流程的详细信息。


官方提供的案例中,Core Image 还将 10 位的 HDR 视频帧数据自动从 HLG 转化成了 Core Image working space。



图三:CI Image 断点测试中展现的处理流程


使用 MTKView 时,开发者需要以 frame 和 device 作为参数重载 init 方法。VIew 对应的 CIContext 也将在 init 函数中被创建。如果我们在 macOS 中开发支持 HDR 的 view,color-Pixel-Format 属性需要被设定为 rgba16Float,wants-Extended-Dynamic-Range-Content 属性需要被设定为 true。设定完 init 方法后,开发者需要实现 draw-in view 方法。需要注意的是,此处并未直接将 Metal 材质传入 CIRenderDestination 函数,而是创建了一个会返回 texture 的 block。这使得 CIContext 能在前面的帧尚未完成时将 Metal 工作入队。之后该方法会执行渲染任务(至指定目的地)并创建 command buffer 将当前绘制结果渲染至 view。


本人也亲自尝试了通过 Core Image 处理视频的整个流程。以下案例使用 CIVortexDistortion 滤镜对视频进行逐帧处理并渲染,展示内容包含核心代码、原视频、CI 滤镜处理后视频以及断点测试的滤镜逐帧处理图示。


let filepath: String? = Bundle.main.path(forResource: "test_video", ofType: "MOV")let fileURL = URL.init(fileURLWithPath: filepath!)let asset = AVAsset(url: fileURL)let item = AVPlayerItem(asset: asset)item.videoComposition = AVMutableVideoComposition(asset: asset) { request in    let filter = CIFilter(name: "CIVortexDistortion")    filter?.setValue(request.sourceImage, forKey: kCIInputImageKey)    filter?.setValue(NSNumber(400), forKey: "inputAngle")    filter?.setValue(NSNumber(1200), forKey: "inputRadius")    filter?.setValue(CIVector(x: 700, y: 400), forKey: "inputCenter")    let out = filter?.outputImage    request.finish(with: out ?? request.sourceImage, context: nil)}avPlayer = AVPlayer(playerItem: item)
复制代码


测试核心代码


http://mpvideo.qpic.cn/0bf2pyaamaaapeahvnrdnbpva7wdaz7aabqa.f10002.mp4?dis_k=0f04353de60ce504c1ffc8be4dd1484b&dis_t=1596367310


原视频(笔者本人取材)


http://mpvideo.qpic.cn/0b78siaacaaa3mah22zdnrpvbewdagjaaaia.f10002.mp4?dis_k=fc45165fd0e34a1f15afa120e5501099&dis_t=1596367310


添加 CIVortexDistortion 滤镜后的视频



图四:断点调试时 Core Image 对每帧的处理流程

基于 Metal 构建 Core Image Kernel

使用 CI Kernel 有诸多优势,包括上文提及的缩短 runtime 编译时间、高性能语言特性(如 gather-reads、group-writes、半精度浮点数)、高效开发体验(如缩进检查、缩进高光)。基于 Metal 构建 CI Kernel 有 5 步流程,会在下文进行逐一介绍。

在项目中增加自定义构建规则

苹果官方推荐在项目 target 中增加两项自定义构建规则。第一个构建规则针对以“.ci.metal”为后缀名的文件。该构建规则会创建一个以“.ci.air”为后缀名的二进制输出文件。



图五:针对“*.ci.metal”文件的构建规则


第二个构建规则针对以“.ci.air”为后缀名的文件(上一个构建规则的输出结果)。该构建规则会在 app 的资源文件夹内创建以“.ci.metallib”为后缀名的输出文件。



图六:针对“*.ci.air”文件的构建规则

在项目中增加.ci.metal 资源

在 Xcode 提供的创建面板中选择 Metal File 即可。开发者对 Metal File 进行命名时需要以“.ci”作为后缀名,这样项目中新生成的文件会以“.ci.metal”作为后缀名。

编写 Metal Kernel

便携 Metal Kernel 需要 include CoreImage.h 头文件,用来使用 Metal 和 Core Image 提供的各种类。官方提供的范例编写了一个 CIColorKernel,输入参数为 coreimage::samle_t 对象(表示输入图片的一个像素)、time 和 coreimage::destination 对象,返回 float4 像素。



图七:苹果官方提供的代码范例:Metal Kernel 编写


苹果官方为开发者提供了描述 CI Kernel 中 Metal Shader 语言的文档,详情见「 Metal Shading Language for Core Image Kernels」① 。

加载 Kernel 并应用于新图像(基于 Swift)

Kernel 会被 CI 滤镜的子类使用。苹果官方推荐开发者在实例化滤镜的 CIKernel 对象时使用静态属性(static property),这种情况下加载 metallib 资源的工作仅会执行一次(在首次需要时)。CI 滤镜的子类也必须重载输出图片的属性,Kernel 将在 getter 中进行图像处理并创建新图像。



图八:苹果官方提供的代码范例:Kernel 加载与使用

Core Image 的 Debug 支持

苹果官方在 WWDC20 详细介绍了 Debug 特性:CI_PRINT_TREE。

什么是 CI_PRINT_TREE

CI_PRINT_TREE 的基础框架与 Xcode 提供的 Core Image Quick Look 支持相同。Core Image Quick Look 为开发者提供了快捷可视化的 Core Image 图片(详见上文图三),而 CI_PRINT_TREE 支持几种不同的模式和选项用来查看 Core Image 如何优化和渲染图像。

如何启用 CI_PRINT_TREE

苹果官方提供了 CI_PRINT_TREE 的两种启动方式。最常用的方法是编辑 Xcode target scheme,在 Arugments 窗体下的环境变量列表中加入 CI_PRINT_TREE 并设置值。另一种方法是在 Terminal.app 中通过命令行启动 CI_PRINT_TREE(需要在执行应用程序前设定)。




图九:启用 CI_PRINT_TREE 的两种方式

如何控制 CI_PRINT_TREE

CI_PRINT_TREE 的字符串格式为“<graph type> <output type> <options>”


  • graph type: 表示 Core Image render 的若干 stage,包括 type-1 初始图像(有助于查看被使用的色彩空间)、type-2 优化后的图像(有助于查看 core image 对 render 的优化效果)、type-4 级联图像(有助于查看各 stage 如何级联于 GPU 程序,以便了解 render 需要多少中间缓存)以及 type-7(输出图像 type1、2 和 4)。



图十:苹果官方对 graph type 四个 stage 的描述


  • output type: 输出格式可以是 pdf 或 png。在 macOS 上 trees 会被存储在临时项目文件夹,在 iOS 上 trees 会被存储在文档(Documents)目录下。如果 output type 没有确定,core image 会把 tree 以紧凑文本格式输出在标准输出(stdout)。通过设置 CI_LOG_FILE=“oslog”,文本也可以前往 Console.app(在 iOS 开发中更为方便)。

  • options: 对于 CI_PRINT_TREE,开发者可以设定额外的选项。如通过设定 context==name 来限制输出(仅输出名字相同的 context),或是通过设定 frame-n 来框定具体输出 context 的哪一帧。更多 option 及详情请见图十一。设定 option 对 debug 能提供很大帮助,但也需谨慎使用,因为生产这些文件需要额外的时间和内存。



图十一:苹果官方提供的 option



图十二:type 设定为 7 时 tmp 文件夹下的文件

如何获得 CI_PRINT_TREE 文件

在 macOS 中,开发者只需要进入“/tmp”文件夹就能找到生成的 CI_PRINT_TREE 文件。需要注意的是沙盒应用会使用特有的临时存储文件夹。


在 iOS 中,开发者需要将 Custom iOS Target Properties 中的“Application supports iTunes file sharing”项设为 YES(图十三)。这样生成的 CI_PRINT_TREE 文件可以在连接中的 iOS 设备上被找到并拖拽至 macOS 存储中。



图十三:Custom iOS Target Properties 中进行设置

如何解释 CI_PRINT_TREE 文件

读 CI_PRINT_TREE 时,需要遵循以下规则:


  • 输入在底层,输出在顶层

  • 绿色节点代表卷曲内核(warp kernel),红色节点代表颜色内核(color kernel)



图十四:绿色节点与红色节点示例


  • 在树的初始位置(initial tree)很容易找到颜色搭配节点(colormatch nodes),里面记录了搭配前后的色彩空间名称。苹果官方提供的案例为 ITUR_2100_HLG_to_workingspace,即 HLG 色彩空间转化为 Core Image 线性色彩空间。



图十五:苹果官方案例中 initial tree 对色彩空间的描述


  • 每个节点会显示 Region of Interest(ROI),表示该节点在 render 中被使用的范围。


如果开发者在 CI_PRINT_TREE 控制字符串中选择 type-4 并在 option 中设定 dump-intermediates,产生的级联图片会展示中间缓存的每一次 pass(除了 output pass)及其耗时、像素点数量和像素点格式(用来查找耗时大、占内存大的 pass)。这对 render 内追踪错误非常有帮助。如果树中没有展示中间图,那么说明这张图在先前渲染的时候已被缓存,因此 Core Image 没有渲染它的必要。



图十六:设定 dump-intermediates 的 debug 效果展示

Core Image 在手淘图片库中的应用可能

手淘图片库中的 CDN 图片适配处理库(TBCDNImage)的核心目的是为不同终端设备、网络环境下的图片展示提供最优解。目前考虑的维度主要是终端设备硬件和网络状态,考虑的参数则是图片尺寸、压缩比率、锐化等图片属性。随着苹果在 Core Image、端智能(CoreML)、硬件支持(自研芯片)等方面进行技术提升,手淘的 CDN 图片适配处理库可以考虑增加“图片内容”作为新的维度,增加亮度、对比度、滤镜、图片种类等新参数。以下为部分应用场景:


  • 识别亮度较暗的图片,提升亮度做 CDN 图片适配处理

  • 判断图片内容种类(如美食),根据不同内容种类的图片增加适合的滤镜做 CDN 图片适配处理

  • 根据移动终端设备屏幕亮度(或深/浅色模式)修改图片色调做 CDN 图片适配处理,达到护眼效果

对 Core Image 技术的展望

总结全文,WWDC20 对 Core Image 技术的提升主要在三方面:


  • 优化 CI 对视频/动图的支持,包括开发流程简化、逐帧处理性能提升等。

  • 允许开发者更自由的构建 Core Image Kernel,使 CI 的特效处理更加丰富

  • 针对 CI 开发流程提供更高效的 Debug 支持


随着苹果未来自研芯片的底层硬件支持将提供视频流流畅的逐帧处理与渲染。笔者认为 Core Image 技术将会在以下场景有较大应用价值:


  • 直播滤镜/特效功能原生化(摆脱自研或第三方 API),实现质量更高的实时滤镜渲染

  • 视频拍摄增加滤镜功能(如淘宝或咸鱼的商品视频录制)


参考:


https://developer.apple.com/metal/MetalCIKLReference6.pdf


https://github.com/duzhaoquan/ImagesVideoFilters


本文转载自公众号淘系技术(ID:AlibabaMTT)。


原文链接


https://mp.weixin.qq.com/s?__biz=MzAxNDEwNjk5OQ==&mid=2650409336&idx=1&sn=f630ee519d7b9fe89807f06484e614b9&chksm=8396c160b4e14876c10c3fd7ac34935582b64f398cb1fd46522bc2ad7c44b06a1602a6f07eb5&scene=27#wechat_redirect


2020-08-09 10:001843

评论

发布
暂无评论
发现更多内容

2021年您应该知道的技术之一!Java工程师一天工作多久

策划Java工程师

Java 程序员 面试 后端

Java磁盘文件IO

文件I/O

各国纷纷推出数字货币,数字货币发展正当其时

CECBC

毕业总结

请弄脏我的身体

架构实战营

Introduction to the Keras Tuner

毛显新

tensorflow

外包学生管理系统的架构设计

架构0期-Bingo

2021春招BAT面试真题详解,从单体式架构迁移到微服务架构

策划Java工程师

Java 程序员 面试 后端

Fil行情:什么时候投资fil合适?

区块链 分布式存储 IPFS fil fil行情

牛客网爆火!面试命中率高达 90% 的阿里 10W 字面试笔记已被疯传

Java 程序员 架构 面试 计算机

Text classification with TensorFlow Hub: Movie reviews

毛显新

tensorflow

【翻译】数据包的旅程 - 关键角色

luojiahu

交换机 路由器 OSI模型 ARP协议

程序员专属的搜索主页

程序员阿杜

搜索技巧 搜索引擎;

开发者必备神器,你真的会用吗?

Jackpop

熬夜整理的c/c++万字总结(一)

C语言与CPP编程

c c++

区块链产业政策红利加速释放

CECBC

2021春招面试,mysql自增主键最大值

策划Java工程师

Java 程序员 面试 后端

揭开进程的概念、状态、通信的迷雾。看完瞬间豁然开朗

Linux服务器开发

线程 网络编程 Linux服务器开发 Linux后台开发 进程管理

程序员有哪些不可或缺的效率神器?

Jackpop

开发

想要跳槽拿高薪,却没有大型性能调优经验怎么办?淘宝架构师手把手带你前进

Java架构师迁哥

网络安全现状,一个黑客真实的收入

网络安全学海

黑客 网络安全 信息安全 渗透测试 漏洞分析

「SQL数据分析系列」13. 索引和约束

Databri_AI

sql 分布式

Druid 查询返回引擎版本困惑的地方

HoneyMoose

Drools 入门

LeifChen

drools 规则引擎 8月日更 业务规则

音视频详细学习路线和权威资料

hanaper

音视频 ffmpeg 语音识别 语音合成 图形图像处理

2021春招BAT面试真题详解,mysqlloaddata自增id

策划Java工程师

Java 程序员 面试 后端

redis,memcached,nginx网络组件

赖猫

nginx redis memcached 网络组件

阿里面试官把以往的Java面试题全部总结在这份《Java10W字面试复盘笔记》里面了

Java 程序员 架构 面试 计算机

操作系统--虚拟内存

en

体验设计工具:18格窗口

石云升

用户体验 7月日更 体验设计

北鲲云超算平台如何提高高性能计算在云环境下的可行性?

北鲲云

Tensorflow日常随笔(一)

毛显新

tensorflow

Core Image:iOS图像处理技术追踪_软件工程_张若舟(越伯)_InfoQ精选文章