QCon 演讲火热征集中,快来分享技术实践与洞见! 了解详情
写点什么

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:001877

评论

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

耗时半年,堪称奇迹!阿里架构师整合出258W字Java全栈面试题

钟奕礼

Java 编程 程序员 架构 java面试

干货 | Chrome 浏览器+Postman还能这样做接口测试 ?

霍格沃兹测试开发学社

Chrome已实现对H.265/HEVC的硬解支持

微帧Visionular

不下载软件,可以把电脑本地文件快速传到远端服务器里吗?

行云管家

服务器 云端 远程 本地

运维去大公司好还是小公司好?你怎么看?

行云管家

运维 IT IT运维

历经70+场面试,我发现了大厂面试的bug,并总结其中心得

钟奕礼

Java 编程 架构 java面试

直播回顾|容器如何提升应用的稳定性?(附PPT下载)

BoCloud博云

云计算 容器 云原生

严禁外传,字节跳动2022秋招Java岗位架构师面试题(暂定版)发布

钟奕礼

Java 编程 程序员 架构 java面试

开源公开课丨ChengYing安装原理剖析

袋鼠云数栈

工赋开发者社区 | Transformers如何用于遥感?阿联酋MBZUAI最新《Transformers遥感处理》综述,涵盖60+种ViT遥感方法

工赋开发者社区

神器 SpringDoc 横空出世!最适合 SpringBoot 的API文档工具来了

Java快了!

SP【ring

袋鼠云产品功能更新报告01期丨用诚心倾听您的需求

袋鼠云数栈

数字藏品:为什么这么火爆,那么多人购买?

开源直播系统源码

区块链+ NFT 数字藏品 数字藏品开发 数字藏品系统

Java 序列化10倍性能优化对比测试

FunTester

真的香!这份《Java面试题库大全》在Github一夜爆火后直接被各大厂要求封杀!

钟奕礼

Java 编程 架构 java面试 技术宅

字节前端二面高频面试题

loveX001

JavaScript 前端

干货 | APP自动化Android之属性获取与断言

霍格沃兹测试开发学社

干货 | Docker 还可以搭建Web服务器nginx ?这么宝藏的吗?

霍格沃兹测试开发学社

HiveServer2 内存泄漏问题定位与优化方案

Java-fenn

Java Java 面试 #java

干货 | H5性能分析实战来啦~

霍格沃兹测试开发学社

ChunJun Meetup演讲分享 | 基于袋鼠云开源框架的数仓一体化建设探索

袋鼠云数栈

5000页?一份字节跳动Java面试全解手册发布!瞬间登顶各大搜索栏

钟奕礼

Java 编程 架构 后端 java面试

大数据和人工智能离不开云计算,他们之间有什么关系?

Finovy Cloud

人工智能 云计算 大数据

实战 | 电商业务性能测试(二): Jmeter 参数化功能实现注册登录的数据驱动

霍格沃兹测试开发学社

面试以前上司,能力一般,不想给他通过,但他卑微哀求,怎么办?

钟奕礼

Java 编程 架构 面试 后端

字节架构师离职后,熬夜整理55W字Java面试手册,逆风翻盘进阿里

钟奕礼

Java 编程 架构 后端 java面试

GitHub永远的神!“阿里爸爸”终于总结出15W字Java源码真题手册

钟奕礼

Java 编程 架构 java面试 技术宅

泪洒阿里,面试惜败闭关2月金九银十再战Alibaba!

钟奕礼

Java 编程 架构 后端 java面试

字节码增强技术之 Java Agent 入门

Java快了!

java;

LED显示屏有哪些让你无法拒绝的优点

Dylan

LED显示屏 户外LED显示屏

真的强!来自扫地僧总结的39W字上千道Java一线大厂面试题手册,成功助我拿下蚂蚁金服offer!

钟奕礼

Java 编程 架构 后端 java面试

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