写点什么

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

评论

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

Python 中 sorted 如何自定义比较逻辑

zikcheng

Python sorted cmp

第三章: 产品解决方案作业

让时间说真话

产品经理 产品经理训练营

话题讨论|过年回家你带电脑吗?

熊斌

话题讨论 28天写作

时间约束帮助我写作

Justin

方法论 创意 习惯养成 28天写作

高性能缓存 Caffeine 原理及实战

vivo互联网技术

Java Caffeine 本地缓存

厚积薄发!华为云7篇论文被AAAI收录,2021年AI行业技术风向标看这里!

华为云开发者联盟

人工智能 卷积网络 远程监督 域泛化 油气储集层收集

不要在nodejs中阻塞event loop

程序那些事

node.js Event 事件循环 程序那些事 nodejs event

云原生动态周报 | Google推出VM Manager

华为云原生团队

Docker 开源 云原生 华为云

第三章:产品解决方案作业

让时间说真话

产品经理

产品经理训练营第0期-第三次作业

孙行者

第0期 产品经理训练营 问题

用RabbitMQ了好几年之后,我总结出来5点RabbitMQ的使用心得

四猿外

MQ RabbitMQ 消息队列

第十周 学习总结

简简单单

史上最清晰的Tarjan算法详解

华为云开发者联盟

算法 静态分析 语法树 Tarjan 数据流

Elasticsearch 写一致性原理

escray

七日更 28天写作 死磕Elasticsearch 60天通过Elastic认证考试 2月春节不断更

前端面试必备ES6全方位总结

我是哪吒

程序员 面试 大前端 ES6 2月春节不断更

华为云FusionInsight助力宇宙行打造金融数据湖新标杆

华为云开发者联盟

数据湖 云原生 存储 FusionInsight 华为云

说说常常被研发忽略的原型模式

后台技术汇

28天写作 2月春节不断更

大背景 (28天写作 Day25/28)

mtfelix

28天写作 新能源汽车 新能源革命 碳中和

第十周 模块分解作业

简简单单

【WOW.js】Animate.css的黄金搭档

德育处主任

CSS 动画 js 28天写作 2月春节不断更

ModelArts AI Gallery与HiLens Kit联合开发丨行人社交距离风险提示Demo

华为云开发者联盟

华为云 modelarts hilens 行人 社交距离

就算知道了答案,真的会改变吗?「幻想短篇 25/28」

道伟

28天写作

安卓开发软件有哪些?分析Android未来几年的发展前景,吐血整理

欢喜学安卓

android 程序员 面试 移动开发

挖矿系统APP源码搭建

luluhulian

挖矿区块链_什么是挖矿 带你详细了解挖矿基础知识

v16629866266

官宣了!Apache ECharts 毕业成为 Apache 软件基金会顶级项目!

百度Geek说

百度 基金会

使用pgBackRest并行归档解决wal堆积问题

PostgreSQLChina

数据库 postgresql 开源 开源社区

安卓开发交流!一线互联网移动架构师筑基必备技能之Java篇,Android岗

欢喜学安卓

android 程序员 面试 移动开发

OpenAI将k8s扩展至7500个节点以支持机器学习;Graph Diffusion Network提升交通流量预测精度

京东科技开发者

区块链 开源

日记 2021年2月2日(周二)

Changing Lin

个人感悟 2月春节不断更

产品训练营 第三次作业

Wangyunnfei

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