大多数浏览器和
Developer App 均支持流媒体播放。
-
相机拍摄和照片分割功能改进
AVCapture API 中新增的强大功能可让您同时从多个相机拍摄照片和视频。照片现在可以从语义分割中获益,您可以借助这项功能来分离照片中的头发、皮肤和牙齿。了解如何利用这些增强功能来创建出色的相机 app,并轻松实现惊艳的照片效果。
资源
相关视频
WWDC19
WWDC17
-
下载
下午好 欢迎来到会议 225 我叫 Brad Ford 我在摄像头软件团队工作 感谢你们 一直坚持到最后 我知道这是很漫长的一天 我们非常感谢你们 能和我们一直待到这个深夜秀 作为一个五点的会议 这个真的很不错
我们今天会介绍 两个 iOS Camera Stack 新的增加功能 我会用最开始的 40 分钟左右 介绍多摄像头摄制 然后我会邀请 Jacob 和 David 上来谈一谈语义分割 首先 多摄像头摄制 或者用我们内部的方式称呼它 多摄像头
多摄像头是我们 最常被需求的第三方性能 我们在实验室每年都能听到这个需求 所以我们现在谈论的是 同时摄制在多摄像头和 麦克风的 视频 音频 元数据 深度和照片 然而 第三方 并不是从中获益的唯一一方 我们也有很多 从甲方获得的重复的需求 也是针对多摄像头摄制的 其中最重要的是 ARKit 如果你听了主旨演讲 你听到了关于 ARKit 3 的介绍 这些 API 使用前置摄像头 用于脸部和姿势追踪 后置摄像头则用于 环境追踪 这让它们可以 根据你在看的地方 知道如何在场景中放置虚拟的角色 所以在 AVFoundation 首次出现之后 我们在 Mac 上支持 多摄像头 Lion 系统也同样支持 但是在 iOS 上 AVFoundation 还是 限制客户 一次使用一个活跃的摄像头 这不是因为我们吝啬 我们对此有我们的理由 第一个理由就是硬件限制 我讲的是 摄像头分享电源轨 它不能同时 全径地位两个摄像头 提供电量 第二个原因就是 我们想要提供一个可靠的 API 这个 API 可以 在同时运行 多个摄像头时 不让手机损坏 所以我们想要确保 我们为你提供了 可以帮助你处理硬件 热量以及带宽限制等 真的存在于我们现实生活中的东西
好了 在 iOS 13 中的一个好消息 我们终于可以支持多摄像头摄制 我们在所有最近的硬件上 都可以实现这一点 iPhone XS XS Max XR 和新的 iPad Pro 在所有这些平台上 之前提到的硬件限制 都已经被解决了 谢天谢地 让我们直接来看看有趣的事情 我们为了构建 MultiCamSessions 有一套新的 API
如果你之前为摄像头摄制 使用了 AVFoundation 你可能知道我们有 四个主要的类 分别是 inputs outsputs session 以及 connections AVCaptureSession 是我们的中心 就是它负责排列数据 你通过它来 启动或停止运行
你将其加入一个或 更多的输入 AVCaptureInputs 其中一个就是 AVCaptureDeviceInput 它对于一个摄像头或一个麦克风 是一个包装器
你还需要增加一个或更多的 AVCaptureOutputs 来获取数据 不然的话 那些发生器没有地方来放置它 然后这个会话将自动代表你 在与媒体类型兼容的 输入和输出之间创建联系 所以请注意 我在这里展示给你的是传统的 AVCaptureSession 它在 iOS 上只允许 一个会话一个摄像头输入
现在在 iOS 13 中我们引入了 一个名为 AVCaptureMultiCamSession 的 AVCaptureSession 的子类 这可以让你做多重输入和输出 AVCaptureSession 不是弃用了 它不会离去 实际上 现存的 AVCaptureSession 在你运行单一的 摄像头摄制时 它仍然是优先的类 这样做的原因是因为 MultiCamSession 作为一个 电源工具 拥有一些限制 这些我一会再说
好的 让我给你们讲述一个 关于我们的新的 AVCaptureMultiCamSession 的 主要的例子 如果说你们想要为 MultiCamSession 增加两个设备 一个是针对前置摄像头 一个针对后置摄像头 同时对 VideoDataOutputs 运行两个 一个从后置摄像头接收画面 一个从前置摄像头接收画面
然后如果你想要 做一个实时预览 你可以分别增加 VideoPreviewLayers 一个是为了前置一个是为了后置
你不需要再那里停止 你可以进行同时的 MetadataOutputs 如果你想要同时进行 扫条形码或面部识别 你可以进行多重 MovieFileOutputs 如果你想要 分别记录前置和后置 如果你想要不同的摄像头 进行实时照片摄制 你可以增加多个 PhotoOutputs 正如你所见 因为有很多箭头 从很多输入 到很多输出 这些图表 看起来很复杂 这些小箭头被称为 AVCaptureConnections 它们从一个输入到一个输出 定义数据流 让我放大一下 看看设备输入 以此来阐明连接的剖析
摄制输入拥有 AVCaptureInput 端口 我喜欢将其视为 小的插座 你可以在每一个媒体类型 拥有一个输入可以生成的出口 如果没有东西插入这个端口 那就没有数据从那个端口流出 就像一个插座一样 你需要插入一些东西来获得电量 现在 为了寻找 对于一个特定的输入来说 什么是可行的端口 你可以查询输入的端口的属性 它将会告诉你 我有 AVCaptureInput 端口的阵列 对于双摄像头 这些就是你会找到的端口 一个用于视频一个用于深度 一个用于如条形码扫描和脸部扫描等 元数据对象 一个用于可以连接至 MovieFileOutput 的元数据项目
当你使用 AVCaptureSessions addInput 方法 来为会话增加一个输入 或 addOutput 来为会话增加一个输出 会话都会寻找可兼容的媒体类型 同时如果可以的话 暗中形成给连接 所以这里 我们有一个 VideoDataOutput VideoDataOutputs 接收视频 接受视频 我们有一个可以生成视频的插头 所以这个连接就自动形成了 这是你们中大部分人 如果之前与我们的类工作过 是如何适应与 AVCaptureSession 工作的 MultiCamSession 是一个不一样的东西 这是因为输入和输出 你有多个 拥有多重输出的输入 你可能想要保证 连接是从 A 至 A 或者从 B 至 B 同时也不会干涉 你不打算让它们做的任务 当构建一个 MultiCamSession 时 我们劝你 不要使用隐式连接生成 而是使用这些特殊的增加器 addInputWithNoConnections 或者 addOutputWithNoConnections 还有类似的你可以用于 VideoPreviewLayer 那就是 setSessionWithNoConnections 当你使用这些的时候 它基本上会告诉会话 这是那些输入 这是那些输出 现在你了解它们了 但是不要去触碰它们 我之后将要按我想的手动 安装连接 你这样做的方法是 通过告诉它 我想要你连接这个端口 或者连入这个输出 来创建 AVCaptureConnection 然后你可以告诉会话 请增加这连接 现在可以了 这个非常冗长 比起口头上说说也许展示一下更好 所以我要有请 Nik Gallo 他也来自于 Camera Software 团队 他将为我们展示 AVMultiCamPiP Nik 谢谢你 Brad
AVMultiCampPiP 是一个 同时展示前置和后置摄像头流的 一个 App 在这里 我们有两个视频预览 一个显示了前置摄像头 一个显示了后摄像头 当我点击两次屏幕 我可以交替 哪个摄像头是全屏的 哪一个出现在 Pip
好了 现在 我可以看到 Brad 在 Apple Park 直播 在我问他几个问题之前 我会按下底部的 记录按钮 然后就可以之后再看这个对话了
你好 Brad 跟我说说在 Apple Park 发生了什么吧 Nik 现在在 Apple Park 非常的混乱 你可以看到在倒影池前 正在举办 各种类型的活动 我可以听到水流的声音 这听起来感觉 我随时都会被淋湿 我还可以听到我身后的野生动物声音 好像是鸭子还是什么 我现在真的有点担心我的人生安全 好的 Brad 这看起来 真的很可怕 希望你在那一切安全 好的 谢谢 明白了
现在我们完成了记录影片 我们来看看 刚刚录下的视频
现在我们有这个影片了 正如你所见 我可以在两个摄像头间交替 它可以像我们使用这个 App 时一样交替 这就是 AVMultiCamPiP 把舞台交还给 Brad 谢谢 Nik 很棒的展示
好的 让我们看一看 在 AVMultiCamPiP 的底层 发生了什么 我们有两个设备输入 一个是对前置摄像头 一个是对后置摄像头 正如我之前所提到的它们没有连接 我们还有分别针对两个摄像头的 两个 VideoDataOutputs 还有两个 VideoPreviewLayers 现在把它们放在屏幕上 现在只需要 得到这些 VideoPreviewLayers 然后命令它们使它们 一个在另一个之上 一个尺寸更小 当 Nik 双按它们的时候 我们简单地将它们复位 同时反转 Z 排序 现在在 Metal Shader Compositor 代码中有些 神奇的事情发生了 它使用了那两个 VideoDataOutputs 同时将它们合成 所以更小的 Pip 被安排在一个画面中 它将它们合成在 一个视频缓冲中 然后把它们发送至一个 AVAssetWriter 在这里 它们被记录至 一个影片中的一个视频轨道 这个样例代码现在是可用的 它与这个会话相连 你可以看一看 然后开始你自己的多摄像头摄制 好的 是时候来谈一谈限制了 虽然 AVMultiCamSession 是一个 电源工具 但它不是万能的 让我来告诉你它不能做的
首先 你不能假装 一个摄像头是两个摄像头 AVCaptureDeviceInput API 会让你创建多个实例 比如说为 后置摄像头 如果你想的话 你可以做十个 但是如果你想要 把所有的实例都 增加到一个 MultiCamSession 它会说 啊嗷 这将引发异常 所以每次会话 在每个摄像头中只有一个输入
还有 你不允许 复制一个摄像头至相同类型的两个输出 比如说用一个摄像头 将它的信号分成 两个 VideoDataOutputs 你当然也可以 增加多个摄像头 将它们分别连接一个 VideoDataOutput 但是你不能让它从一个分散到很多个
你也不允许 反过来这样做 iOS 上的 AVCaptureOutputs 并不支持媒体混合 所以所有的数据输出 只能有一个单一的输入 比如说 你不能 试着把两个摄像头源 挤入一个单一的数据输出 它不知道如何 处理第二个视频 因为它不知道如何混合它们 你当然可以使用 分别的 VideoDataOutputs 然后在你自己的代码中 合成这些缓冲 比如我们在 MultiCamPiP 中使用的 Metal Shader Composite 你可以根据你的喜好来做这些 但是关于会话构建 不要试着将多个摄像头 挤入一个单一的输出
好的 简单说说预设
传统的 AVCaptureSession 拥有会话预设的概念 它决定了整个会话的 服务的一般质量 它应用至那个会话中的 所有输入和输出 比如说 当你把会话预设为高 会话设定设备的 分辨率和帧率以及所有的输出 所以它们在 传送一个高质量的 视频体验 比如说 1080p30
预设是 MultiCamSession 的一个问题 再次想想看起来像这样的事情 MultiCamSession 设定是 混合式的 它们是异构型的 对于整个事情都拥有高质量 意味着什么呢 你可能想要 在不同分支的图表中 拥有不同质量的服务 比如说 在前置摄像头 你可能只是想要一个 低分辨率的预览 比如 640x480 同时还有一些高质量的 比如说 在后置摄像头 是 1080p60 好的 很明显 我们没有为所有这些混合的情况 设定预设 我们决定让事情在 MultiCamSession 保持简单 它不支持多重预设 它支持一个 且只有一个预设 也就是输入优先 所以这意味着 它不干涉输入和输出 当你增加它们时 你必须自己设定活跃的格式 好的 来到 Cost Functions 我在最开始提到了 我们用时间处理了这个 多摄像头支持 因为我们想要传递一个 可靠的 API 它可以帮你 在你运行多个摄像头时 对你遇到的消耗负责 同时实质上点亮手机上的每个块
这很老套但是也很真实 天下没有免费的午餐 所以这一部分 我将成为你们的老爸 然后给你们来一个父亲的谈话
在父亲的谈话中 我会解释信用卡是如何工作的 以及你如何需要对你的钱负责 同时按你的方法生活 诸如此类的事情
事实就是 我们在 iOS 上有 限制的硬件带宽 尽管我们有多个摄像头 所以我们有多个传感器 我们只有一个 ISP 也就是图片信号处理器 所以所有的这些传感器 所有这些通过传感器的像素 都需要被一个单独的 ISP 所处理 在特定的频率下 它由每个小时运行 像素所限制 所以对于你一次 可以运行的像素数 也是有限制器的 HardwareCosts 的贡献者 正如你所期待的 是视频分辨率 高的分辨率意味着 更多的像素塞满在这里 最大的帧率 如果你更快地 传递这些像素 每个小时也会有更多的像素 然后是第三个 你可能听过也可能没听过 它的名称是 Sensor Binning
Sensor Binning 指的是 将相邻像素中的 信息结合在一起来降低带宽 比如说 如果我们这里有一个图像 我们进行一个 2x2 的合并 它在正方形中有 4 个像素 然后将它们加成一个 这样我们可以在尺寸上减小四倍 这让你减少了噪点 同时也减小了带宽 它在每个像素给了你 4 倍的强度 关于 Sensor Binning 有很多很好的东西 缺点就是 在图像质量上会有一些降低 所以对角线可能 有点像楼梯 但是它们最补偿的质量就是 合并像素的格式是很低功率的 实际上 无论你什么时候 与摄像头一起使用 ARKit 你使用的都是一个合并像素的格式 因为 ARKit 只有在 为了你喜欢的做的那些 有意思的 AR 效果节省能源时 才会使用合并像素格式
好的 我们如何说明这些消耗 或者说我们如何报告这些消耗呢 在你配置你的会话时 MultiCamSession 会结算你的 HardwareCost 所以每次你改变一些东西时 都会有所记录 就好像填满购物车 或者说去网上购物 在你付款之前 将所有东西都放入购物车 你知道你什么时候 会接近你预算的极限 然后你就可以尝试了 把新的事物放进来 或者将旧的东西拿出去 你在支付之前 就能看到花费 MultiCamSession 也是一样的 我们有一个名为 HardwareCost 的新属性 当你制作一个全新的会话时 HardwareCost 起始数值是零
随着你增加更多的性能 更多的输入 更多的输出 它也会随之增加 只要在 1.0 之下 一切都是很好的 一切在 1.0 之下都是可以运行的
一旦到达了 1.0 或者更大 你就麻烦了 这是因为 ISP 带宽限制很难 它不是像你可以 传递每个其他的画面 不是的 这是一个孤注一掷的提议 你要么就成功 要么就失败 所以如果超过了 1.0 而且你试着运行 AVCaptureMultiCamSession 它会说 啊嗷 它会通知你 运行时间错误 这指出了它必须停下的原因 那就是因为硬件消耗过剩
现在你可能在想 我如何才能减少消耗呢 最明显的方法就是 选择一个更低的分辨率 如果你想要保持相同的分辨率 还有一个方法就是 如果在相同的分辨率下 有一个合并像素格式 选择那一个 这个质量可能会更低 但是能源上也低的多 接下来 你可能认为帧率会有所帮助 但其实并不是
原因就是 AVCaptureDevice 允许你 开始允许你 在飞行状态下改变帧率 是从 iOS 4 开始的 所以如果你有一个 120 fps 格式 然后你说 将活跃格式设定为 60 你还是需要消耗120 而不是 60 因为在你运行的任何时候 你都可以将帧率提高至 120 我们必须考虑到最坏的情况
但是好消息就是 我们不会在 AVCaptureDeviceInput 提供覆盖属性 通过这样设定 你可以通过保证 你不会比某个特定帧率高 将一个高帧率 转化为一个低帧率
现在 在我们的 API 上 有一点疑惑 我们讨论帧率时并不将其作为速率 而是作为持续时间 所以为了设定一个帧率 你将一个移交给持续时间 这和帧率是一样的 所以如果你想要一个 60 fps 的 格式并将它做成一个 30 fps 的格式 你将 CMTime 设定为 1 至 30 这也是一个持续时间 然后将 deviceInputs videoMinFrameDurationOverride 设定为 30 fps 恭喜 你刚刚将 60 fps 的格式 改为了 30 fps 格式 你只需要消耗 30 的硬件消耗 我还需要提到一个 在 AVMultiCamPiP App 中的 一个很棒的功能 它可以展示如何迭代低降低你的消耗 这是一个递推的功能 它会选择对它 最重要的事情 同时对不那么重要的事情 进行节流 直到它在 HardwareCost 之下 接下来就是系统压力消耗 这是我们报告的 第二大贡献者 你们应该早有所闻 手机在小的 片段的 热的 挑战性的包中 是功能强大的电脑 在 iOS 11 中 我们引入了摄像头系统压力状态 这可以帮你 监控摄像头现在的状态
摄像头系统压力 包括系统温度 也就是所有的 OS 热量
峰值功率要求 这个和电池有关 它现在有多少电量 它增加电压的速度 是否快到可以 满足无论你现在想做什么的需求
还有红外检测器温度 支持 TrueDepth Camera 的设备上 我们有一个红外线摄像头 也有一个 RGB 摄像头 好的 这个会生成自己的热度 这就是对系统压力状态的 一部分贡献 我们有五个状态 从标称一直到关机 当系统压力状态是标称时 你的状态是良好的 你可以想做什么就做什么 当状态是一般时 你可以基本完成你想做的 但是如果是严重状态 你会陷入一个 系统开始放慢速度的境况 这意味着对于 GPU 你们有着更少的时间间隔 你们的质量 可能会被打折扣 在非常严重状态 你们将会有很大的节流 在关机状态 因为担心伤害硬件 我们将不再能运行摄像头 所以在关机状态 我们会自动中断你的会话 停止它 告诉你 你因为一个系统压力状态而被中断了 然后我们就等待设备 一直回到标称状态 然后才能继续运行摄像头
这就是所有的 iOS 11 现在 在 iOS 13 中 我们给你提供一个 在前方负责系统压力消耗的方法 好吗 我们不会告诉你 现在发生了什么 如果你在玩部落冲突之后 开启摄像头 那这个可能会被影响 我们现在有一个方法 可以告诉你就系统压力而言 摄像头消耗是什么 不依赖于 所有其他的因素 对于这个消耗的贡献者 和对硬件的贡献者是一样的 与其他很多一起 比如视频图像稳定 或者光学图像稳定 所有这些都消耗能量 我们有个 Smart HDR 性能等等 所有这些列在这的 都是对全部 系统压力消耗的贡献者
MultiCamSession 可以在最前面 结算分数 就像它对硬件做的那样 它只会解释它了解的因素 如果你想同时 做一些不合情理的 GPU 运行 分数不会将其包含 它只会包含 你对摄像头的操作 这是你如何使用它的方法
通过查询 systemPressureCost 你可以找到 你在一个相对静止的系统中 可以运行多长时间 如果是少于 1.0 你可以一直运行 你是一个冷静的顾客 如果在 1.0 和 2.0 之间 你可以运行最多 15 分钟 2.0 到 3。0 之间 最多 10 分钟 高于 3.0 你可能只能运行一小会 实际上 即便你超过了 3 我们会让你运行摄像头 但是你需要明白 它不会一直保持冷静 它一旦到达 非常严重或者关机等级 你的会话将被中断 所以我们会保存硬件 即便你不想 但是这非常棒 如果你能在运行的 30 秒内 使用非常高的系统压力消耗 得到你需要的做的 无论用什么方法都去做
现在你如何在运行的时候 降低你的系统压力呢 我讲的不是 当你在设定你的会话的时候 我讲的是一旦你 开始运行而且你注意到 你开始在系统压力中有所升高 最快和最简单的方法 就是迅速地降低帧率 这会缓解系统压力 同时 如果你做的事是我们不知道的 比如说 繁重的 GPU 或 CPU 工作 你可以减慢它的速度 作为最后的一个手段 你可能试着停用 你使用的一个或更多的摄像头 AVMultiCamSession 有一个 有序的小性能 在运行的时候 你可以在不影响其他预览的情况下 停用一个摄像头 我们不会把所有都关闭 比如说 你在运行前置和后置摄像头 你注意到你已经超预算了 你很快就要到达非常严重等级了 你可以选择 关闭前置摄像头 后置摄像头还会继续预览 它不会失去它的焦点 曝光 或者白平衡 当你通过设定 摄像头的输入端口 enabled 为 false 来关闭摄像头上的最后一个活跃的输入端口 我们将停止 那个摄像头流 同时保存很多能量 并给系统一个机会冷却
好的 我刚刚讲到了两个 非常重要的消耗 硬件和系统压力 还有其他 我们没有报告的消耗 我不想哄骗你去相信这里 没有其他东西在工作 当然有其他的消耗了 比如说内存 但是在 iOS 13 我们人工地限制了 我们允许你们运行的设备组合 这些是我们相信 你会运行的 这不会让你陷入麻烦
所以支持设备组合 是有限的 现在 我要列出 在 iPhone XS 上被支持的组合 这个看起来就像一个视力检查表 我不指望你们能记住 你们可以之后暂停视频 但是有六个支持的配置 有个简单的规则要记住就是 你可以同时运行 两个实体摄像头 你可能会疑问 Brad 配置一号 怎么样 那里只有一个复选框 这是因为双镜头 双镜头是一个 软件摄像头 由广角和长焦镜头构成 这是两个实体摄像头
你如何找出多摄像头是否被支持呢 正如我说的 它只有在更新的硬件上才会被支持 所以你需要确认 MultiCamSession 是否会让你 运行多个摄像头 或者不在你有的那个设备上运行 有一个名为 isMultiCamSupported 的类方法 你可以快速地决定 是还是否 进一步的 当你要决定 我是否允许一起运行这些设备的组合 你可以创建一个 AVCaptureDeviceDiscoverySession 与你感兴趣的设备一起 然后就要求它的新性能 supportedMultiCamDeviceSets 这将引进一个 告诉你哪个你可以一起使用的 无序的集合的阵列
接下来就是 我们人工地限制 你允许运行的格式的方法 支持的格式 上一个是我在 iPhone XS 上检查的 那里在后置摄像头上 有超过 40 的格式 所以有很多可以选择 但是我们限制了 可以与 MultiCamSession 运行的 实际的视频格式 因为这些是我们可以 同时在一个终端设备 运行的 再一次 这个有点像视力表 但是我将要 把你们的注意力转向群组 第一个群组是 合并像素格式 记得低功率吗 是的 它们是我们的朋友 在传感器 你会获得 2x2 的合并像素 所以你的能耗 是很低的 所有这些最高到 60 fps 都是可行的 你的选择从 640x480 一直到 1920x1440 下一个群组就是在 30 的 1920x1080 这是一个没有合并像素的格式 如果你在常规传统会话中 选择了高预设 你得到的将和它一样 这个对于 MultiCam 是可行的 最后一个是 1920x1440 在 30 fps 是不合并的 这个对于照片格式来说 是一个很好的替换 我们在终端摄像头上 不支持 12 兆像素 它对于手机 会有一些不好的影响 但是我们允许你 在 30 fps 时像素是 1920x1440 请注意它还会让你 使用 1200 万像素 如果你想要 同时用多个摄像头进行拍摄 这是一个很好的代理技术 现在 你要如何确认 一个格式是否支持多摄像头呢 你只需要问即可 所以在格式中迭代时 你可以声明 isMultiCamSupported 如果是的话 你可以使用它 在这个代码中 我在一个设备中迭代格式 选择下一个 分辨率最低的并且支持多摄像头的 然后将其设定为我的活跃格式 最后一个我们人工限制 就是因为我们需要报告消耗 那些消耗是由 MultiCamSession 报告的 我们明确地 在一个 App 中不支持 拥有多摄像头的 iOS 多会话 我们同样在多个 App 中 不能支持 多个摄像头 请注意在 iOS 上的支持 还是一次只限制于一个会话 不过当然了 你可以一次运行多个摄像头 父亲谈话到此结束好吗 写好的代码 十一点前回家 如果你的计划改变了 打我电话 好的 我们现在继续回到一些有趣的事情
同步的数据流 我只讲了一点点 关于软件摄像头的事 双摄像头是一个 在 iPhone 7 Plus 被导入 它现在也在 iPhone XS 和 XS Max 上展示 TrueDepth 摄像头 是另一个类型的软件摄像头 因为它由一个红外摄像头 和一个 RGB 摄像头组成 通过得到它们两个之间的视差 它可以得到一个深度
现在 我们还没有给 特殊类型的摄像头命名 但是我们现在要这样做了 在 iOS 13 中 我们将其称为虚拟摄像头 DualCam 就是其中之一 它会在某时展示一个视频流 然后会根据 你的放大系数来切换 如果你放大 2 倍 它会转到长焦镜头 而不是广角镜头 它与深度一起还有一些奇招 因为它有两个图像 可以用来生成 它们之间的视差 但是从你的角度来说 你一次还是只能 得到一个流 因为我们现在有了一个名称 它们也是你可以查询的 在 API 上的属性 在你看你的摄像头设备时 你可以以编程方式 去了解这个是否 是一个虚拟设备 如果是的话 你可以询问它 你的实体设备是什么呢 在 API 中我们称其为 constituentDevices
同步的流都是关于 使用一个虚拟设备的 构成的设备 然后同时运行它们 换句话说 首次我们会允许你 同时从广角和长焦镜头 流同步的视频 你继续在虚拟设备上 设定属性 而不是在组成设备上 这是一些适当的规则 当你运行虚拟设备时 组成设备不允许 随意运行 它们拥有相同的 活跃的分辨率 它们有相同的帧率 在硬件方面 它们是同步的 这意味着它们在读出 传感器用同步的方式 读出那些帧率 所以这个读出的 00:31:01.056 --> 00:31:03.376 A:middle 中线的钟表时间
是相同的 所以 这意味着 它们在画面中间匹配 这也意味着曝光 白平衡和焦点是串接的 这样非常好 这让它看上去 感觉像是相同的摄像头 它只是碰巧在 两个不同的视野
事实胜于雄辩 让我们来展示一下 这个是 AVDualCam 好的
AVDualCam 通过向你展示 两个同时运行的摄像头 让你知道 虚拟摄像头看到的 它通过向你展示 这些摄像头不同的视角来实现这点 好的 现在我有 在双摄像头中同时运行的 广角和长焦构成流 左侧是广角 右侧是长焦 不相信我吗 这里 我将把我的手指放在一侧 啊 我将把我的手指放在另一侧 看见了吗 它们是不同的摄像头 我只需要拉近或推远广角镜头 所以它可以和长焦镜头 有相同的视野 但是你可以发现 它们运行的非常同步 这里没有分裂 在垂直遮没中也没有 奇怪的地方 它们的曝光和焦点 同时改变
更有趣的事会发生 如果我们将并排的视图 改成分别的视图 现在 这个有点难观察 但是我在 左边展示广角镜头 在右边展示长焦镜头 我只向你们展示 每个画面的一半
现在如果我点三下 会出现 距离米数 这让我可以改变 两个图像的深度衔接平面 这个 App 知道 如何互相注册两个图像 所以 这个可以让我 玩弄在深度相交的平面 这有点像你眼睛看到的 当你很近地聚焦在某件东西上 或者拉远 你可能会改变平面的深度相交 比如说 贴近我的手 我可以找到 深度相交的很好的地方 开始吧 现在我有一个完整的手了 但是我后面的车则不一样了 所以我可以继续拉远 好的 但是这个对后面的车又不对了 现在我可以把那个也拉回来 这就是双摄像头流 双摄像头的同步
这里有个图展示了 AVDualCam 的图表
它没有分别使用设备输入 而是只有一个 所以它对双摄像头 使用单一的设备输入 但是它用同步的方式 获得广角和长焦画面 应用于两个 VideoDataOutputs 你会注意到这里有一个 小的对象 在底部有个名为 AVCaptureDataOutputSynchronizer 的方块 我不想迷惑你 这个并不会执行 我谈到的硬件同步 如果你想要的话 它只是一个在会话底部的对象 这会让你在一个单一的回调中 同时可以得到 多个回调 你可以不必获得 针对广角和长焦的 单独的 VideoDataOutput 回调 你可以启动 在底部的 DataOutputSynchronizer 通过一个单一的回调 同时得到两个画面 这样非常的便利 在它下面有 Metal Shader Filter / Compositor 这会很魔幻 正如我说的 它知道如何将这些画面混合在一起 它会决定如何 把这些画面 放置在预览的正确位置 它还可以将它们 发送给一个 AVAssetWriter 来保存一个视频轨道
现在回调我之前的图标
我展示给你们一个 AVCaptureDeviceInput 的特写视图 特别是双摄像头 双摄像头输入的端口属性 展示了你刚刚看到的端口
有人在那里看到了 两个视频端口吗 我没有看到两个视频端口 那我们如何从 我们看到的那些输入端口得到 广角和长焦呢 一个视频端口会 给我们两个镜头吗 不 它不会给我们广角或长焦 它给我们的是 双摄像头根据 放大系数决定的 这不会帮助我们 同时得到构成的流 那我们怎么做呢 我来告诉你 但是这是一个秘密 所以你要保证别告诉别人 好吗 虚拟设备拥有秘密的端口 好吗
这些秘密的端口 之前对于你们来说是未知的 现在可以用了 但是你不用把他们拿出 端口阵列 通过了解该问什么 你就可以得到它们 所以 你可以不用 只是得到包括不能 与单一摄像头会话使用的端口的 可达到的端口类型的阵列 你可以通过名称寻找它们 在这里我们有 dualCameraInput 我在寻找 拥有源设备类型广角镜头 和源设备类型 长焦镜头 可以了 啊哈 这些就是我知道的秘密端口 我现在将把它们展示给你们 一旦你得到这些输入端口 你可以用你在 自己的手动连接创作中 相同的方法来 安装至一个连接 然后你就可以从 广角或广角或者两个镜头同时视频流
现在在 AVDualCam 展示中 我可以用正确的视角 改变广角和 长焦镜头 深度会合平面 你会看到那不是 完全的移动或震动 它只是按照我想要的 在平面旁移动 它只是在平面的基线旁 我可以这样做 因为 AVFoundation 给我们提供了 一些单应性帮助 如果你不熟悉 单应性这个词 它和相同的平面上的 两个图像相关联 它们是电脑视角的基础 它们对于如图像校正 图像配准等任务是很普遍的 现在摄像头的内联函数 对于 iOS 来说不是新鲜事 我们在 iOS 11 上引入它们 它们展示在 3x3 矩阵中 矩阵描绘了一个摄像头的 几何属性 也就是在这能看到的它的焦距 它的光心 使用针孔照摄像头 你可以看到它在哪里进入了针孔 然后击中传感器 也就是光学传感器 两者之间的距离 就是焦距
现在你可以通过输入 AVCaptureConnection 并且声明你想选择加入 内部传送 来接受逐帧内联函数 一旦你这样做了 那么每一个你接受的 VideoDataOutput 缓冲都会 拥有这个附件 CameraIntrinsicMatrix 还是一个包含 浮点型矩阵 3x3 的 NS 数据 这是一个 SIMDI 类型 当你得到广角画面 它有针对广角镜头的矩阵 当你得到长焦画面 它有针对长焦镜头的矩阵 现在 在新的 iOS 13 中 我们在设备层面提供了 摄像头外参数 外参数是一个转置矩阵 和一个平移向量 一起填进一个矩阵 这些和参考摄像头相比都描述了 摄像头的姿势 这会帮助你 如果你想要叙述两个摄像头在哪里 包括它们的俯仰 以及它们的焦段 所以 AVDualCam 使用外参数 来了解如何在彼此之间 相对校准广角和 长焦镜头画面 这样它们就可以 进行整齐的视角转换 这是一个非常非常简短的 关于内参数和外参数复习 我在两年前 在演讲 507 中 用非常乏味的细节介绍过它们 如果你很喜欢 双关语的话 你可以去复习一下那个演讲 好的 最后一个关于多摄像头摄制的话题就是 多麦克风摄制 好的 让我们复习一下 麦克风摄制的初始行为 如果它们使用一个传统的 AVCaptureSession 的话
麦克风跟随摄像头 这就和我说的一样简单 所以如果你有一个 接入你会话的前置摄像头和一个麦克风 它会自动选择 和前置摄像头 方向一样的麦克风 后置摄像头也是如此 它会制作一个很好的 心形线曲线图 这样它可以拒绝你不需要的那边的音频 这样 你就可以跟随你的主题 使用前置或者后置 如果你有一个纯音频会话 我们不太确定指导这个音频的方向 所以我们会给你一个 全方向的领域 作为一个功率特性 你可以将它们全部停用 你只需要说 别动 AVCaptureSession 我想要使用我自己的 AV 音频会话 以及配置我自己的音频 我们会尊重这个意愿的 现在我将告诉你们 另外一个小秘密
并没有前置麦克风这个东西 我刚刚是骗你们的
实际上 iPhone 拥有 麦克风阵列 根据不同的设备 有不同的数量 最近的 iPhone 正好有四个 iPad 有五个 它们位于 不同的关键位置 在最近的 iPhone 中 有两个麦克风 位于底部 在上端 有两个在两侧 它们都是全方向的麦克风 现在 上端的麦克风 会有些声音的隔离 因为设备的机身 在它们中间 这就起到了一个挡板的作用 但是它还是没有 给你想要的很好的 方向性模式 所以你要做些什么 可以得到一些接近 前置或后置麦克风的东西
你做的被称为 麦克风波束形成 它可以加工原始音频信号 从而让它们变得 具有方向性 这就是核心音频 在我们这边所做的 在这里 我们有两个蓝点 它代表了一个 iPhone 上 两边的两个麦克风 圆圈大概是 它们听到的音频模型 请记住 它们都是全方向的麦克风 如果我们采用这两个信号 我们只是简单地扣掉它们 我们最后得到了一个像 8 的图形 这很酷 这不是我们想要的 但是很酷
如果我们想要进一步塑造它 我可以在扣除它们之前就 增加一些增益 现在看起来就像 吃豆人幽灵 这样很好 我们在我们不想要的侧端旁边 得到了拒绝 但不幸的是 我们也减弱了信号 所以这个比我们想的声音要小
但是 如果在完成这些之后 我们对那个信号应用了一些增益 我们会得到一个很好的 很大的吃豆人幽灵 现在 我们得到了我们想要的 这个漂亮的心形曲线图 它拒绝了我们不想要的 一侧的摄像头 现在 它已经 过于简单化了 有很多过滤 来确保白噪音 没有上升 但是本质上来说这就是在发生的事情 到目前为止 每一次只有一个麦克风波束形成 可以被支持 但是在核心音频中的 好的东西为这个多摄像头特征 做了一些很好的工作 对于 iOS 13 来说 我们现在支持多个同时的波束形成
所以回到 AVCaptureSession 当你得到一个麦克风设备输入时 你找到了它的音频端口 这个端口可以 在很多地方 根据会话找到的 那个摄像头 它可以在前置 后置或全方位 当你使用 MultiCamSession 时 行为是很严格的 第一个端口 你找到的第一个音频端口 一般都是全方位的 然后你就会找到 我提到的获得专用的后置波束 或前置波束的 秘密端口 你实现这个的方法就是 使用那些相同设备输入端口的读取器 这一次 则是通过指定你感兴趣的位置 所以你可以要求前面的位置 或者是后面的位置 这会给你 你感兴趣的端口 你会得到一个很好的 后置或前置波束形成
这是前置的
这是后置的 现在回到我们之前与 Nik 的 MultiCamPiP 展示 我们向你们展示 图表的技术先进地方的时候 针对的是视频部分 现在我将回到那里 并告诉你们音频部分的情况 我们一直都是 运行有两个波束形成的单一设备输入 一个针对后置 一个针对前置 所以我们将它们运行至 两个不同的音频数据输出 这个幻灯片里应该说的是 音频数据输出 然后在运行的时候 在它们两者间选择 所以根据两者中间 哪个更大 我们可以在后置或前置转换 同时给你我们想要的波束形成
还有一些关于多摄像头摄制的 规则需要知道 波束形成只能与嵌入麦克风工作 如果你有一些 外部的 USB 你不需要知道 我们不知道如何 让波束形成与其共同运行 如果你恰好插入了一些其它东西 包括 AirPod 等 我们当然可以摄制音频 但是我们不知道如何波束形成 我们会将麦克风 在所有你连接的 输入中输送 所以 保证你没有失去信号 这就是今天 关于多摄像头摄制部分的演讲 我们来做一个快速的总结
多摄像头摄制会话 是 iOS 上同时运行多个摄像头的新方法
这是一个电源工具 但是它也有一些限制 了解它们
在你编程的时候 你需要深思熟虑地 处理硬件和系统压力消耗 如果你想要进行 同步的流 使用拥有构成的设备端口的 虚拟设备 最后 如果你想要进行多麦克风摄制 你要知道 你可以使用前置或后置波束形成 或者全方位 谢谢 嗨 我是 Jacob 我在这里要讲的是 语义分割抠像 首先 我要讲一下 这些新型的抠像 然后 David 会告诉你 如何利用 Core Image 来处理这些新抠像 记得吗 iOS 12 中 我们引入了人像效果抠像 所以这是一个 明确地为肖像提供效果 而设计的抠像 所以我们在内部 使用它来渲染好看的 人像模式照片和人像灯光照片 所以在仔细观察 人像效果抠像的时候 你可以清楚地看到它 是如何从背景中勾勒出 前景主体的 这里展示的 是一个很漂亮的黑白抠像 数值 1 表示前景 数值 0 表示背景
在 iOS 13 中 我们在 语义分割抠像上 更进一步
所以我们要介绍头发抠像
皮肤抠像和牙齿抠像 所以 仔细观察一下 00:46:20.046 --> 00:46:21.416 A:middle 头发抠像 例如
你可以看到这是如何漂亮地 从非头发区域 分离头发区域的 所以我们在背景中 得到了很好的头发细节 我们在非头发区域 和头发区域之间得到了很大的分离
类似地 对于皮肤区域 我们现在有 alpha 值 来表示皮肤类型中 有多少像素 例如 alpha 值为 .7 表示一个像素是 皮肤类型的 70% 所以我们希望这三种 新类型的抠像 将给你的创作自由 去渲染一些很酷的 效果和美丽的照片
有几件事需要注意 抠像只有原始图像的一半尺寸 这意味着它们是原始图像 尺寸大小的一半 这意味着四分之一的分辨率
另一件要记住的事是 这些分割的 抠像物体实际上是可以重叠的 所以这对于人像效果抠像 和皮肤抠像来说是特别真实的 因为它们会有内在的重叠
所以这些抠像并不是免费的 所以我们充分利用了 机器学习谱图理论的 Apple 神经引擎 和一些底层的东西 我们要做的就是获取 原始尺寸的图像 我们通过 Apple 神经引擎输入 结合原始尺寸的图像 我们渲染这些 高分辨率 高质量 高一致性的分割抠像 然后就可以将它们 嵌入到已知的 HEIF 或 JPEG 文件中 以及 iOS 11 中 已知的原始尺寸图像和深度 因此 有两种不同的方法 来生成这些抠像的新类型 一个是它们嵌入到 旧的人像模式摄制中 你可以从这些文件中获取它们 或者更好的是你可以编写 自己的摄制 App 并在摄制时选择加入这些抠像 如果你的文件中 有分割抠像 你可以通过 Core Image和 Image IO 来处理 David 会详细讲一下 但首先 我将向你们介绍 如何使用 AVFoundation API 进行摄制
这里我们要 经历四个阶段 这四个阶段 与扩展有关 首先是设置 AVCapturePhotoOutput 第二是当摄制请求 在你的 App 生命周期的任意点 被启动时 然后是两个回调 一个是当设置 为你的摄制解析时 最后一个是 照片处理完成时 所以 关于这个问题的详细信息 请参考 Brad 2017 年 关于这个话题的演讲
好的 让我们来看看 如何设置 AVCapturePhotoOutput 这通常发生在设置或配置会话时 至此 你已经完成了初始配置的会话 你已经设置了你的预置 你已经添加了设备输入添加 AVCapturePhotoOutput 此时你告诉 API 在 App 生命周期的 任何时刻你想要的 分割抠像的父集是什么
当你真正想要 启动摄制请求时 你需要指定 AVCapturePhotoSettings 这就是你告诉API的地方 这就是我在这个特殊摄制中 真正想要的 这里你可以指定 所有你已经激活的 或者可以指定一个子集 比如头发或皮肤
现在 启动摄制请求 你给它 AVCapturePhotoSettings 你在你想要拥有回调的地方 给它委派
所以时间过去了 之后你将得到一个针对回调的摄制 如果你请求某些事 这就是 API 会告诉你的 但是这些不是 你将得到的 这对于人像特效抠像 和语义分割抠像 非常重要 因为如果画面中没有人 你实际上不会得到一个抠像 因此 你需要检查 语音分割抠像的尺寸 在这种情况下是零
更多的时间流逝了 照片处理完毕 这就是你得到 AV 语义分割抠像的时候了 在这种情况下这就是变量抠像 这个新类有相同 类型的方法和属性 正如你在肖像效果抠像中所知道的 这意味着 你可以根据 EXIF 数据 你可以得到你的 CVPixelBuffer 参考 或者你可以获得一个字典 表示的简单文件 IO 因此 要了解如何制作 这些图片的完整步骤 请参考 AVCam 示例 App 它已经更新了 语义分割抠像 并将带你经历所有这些不同的步骤
我将把时间交给 David 他将讨论 Core Image 好的 非常感谢 现在 我们已经学习了 如何使用语义分割抠像 来摄制图像 我们将 从中获得一些乐趣 并学习如何 利用 Core Image 来应用 一些有趣的效果 接下来我要做一个演示 但我要提醒你 这幅图里有小丑 所以 如果你有小丑恐惧症 或者对小丑的非理性恐惧 请转移你的视线 好的 这里我们有一张 设备上用人像模式摄制的图像 在这个 App 中 我们可以很容易地看到 这个文件中 所有不同的 语义分割抠像 我们可以使用传统的 人像效果抠像 或者我们也可以 看到皮肤抠像 或者我们可以看到 头发抠像或牙齿抠像 也可以使用 核心图像将这些 各种各样的抠像组合成其他的 抠像 比如我使用 逻辑操作合成的 这个抠像 只有眼睛和嘴巴 如果我们回到主图像 我们看到 我在 Apple Park 的照片 你可以用人像效果抠像 做的一件很棒的事情 那就是你可以 很简单地添加一个背景 你可以看到 我们可以 把我放在马戏团的帐篷里 虽然那看起来确实像 一个马戏团的帐篷 但我看起来有点违和 现在我们可以使用一些有趣的效果 比如 我们可以让它 看起来像我化了小丑妆 或者如果我们想更进一步 我们可以给自己一些绿色的头发 最后 我们可以用一些 其他的抠像 来给自己化妆
这就是我今天要讲的 我们如何在你的 App 中 实现这些有趣的效果 好了 现在大部分关于小丑的 引用都没有了 所以回看是安全的 好的 我们今天将讨论 三件事 首先是如何使用 核心图像创建抠图图像 如何对这些图像应用滤镜 最后是 如何将它们保存到文件中 首先 让我们讨论 使用核心图像创建抠像图像 有两种方法 其一是可以使用 AVCapturePhoto API 创建抠像图像 然后 从这里 你可以创建一个核心图像 这个的代码很简单 我们要做的是使用 semanticSegmentationMatte API 精确地指定 我们要做的是头发 皮肤 还是牙齿 返回一个 AVSemanticSegementMatteObject 从这里 创建一个CIImage 很简单 我们可以 从对象实例化一个 CIImage
=创建抠像图像的 另一种常见方法 是从 HEIF 或 JPEG 文件 加载图像 这些文件有一个你熟悉的 主映像 一个典型的 RGB 图像 但它们也有辅助 图像 比如人像效果 抠像 以及 我们正在讨论的新抠像 皮肤分割抠像 头发抠像和牙齿抠像
其代码非常简单 从 HEIF 文件创建 CIImage 的传统代码是仅仅 声明 CIImage 并指定一个 URL 要创建这些辅助 图像 你所要做的就是 执行相同的调用并提供 一个选项字典 指定 要返回哪个抠像图像 所以我们可以指定 辅助分割头发抠像细节 或者如果我们愿意 我们可以得到 其他语义分段的抠像
非常简单 只有几行代码 我们接下来要做的是 讨论你如何将效果应用到 这些图像上 我展示了一些效果 我将会详细讨论 其中一个 我们要做的是从一个 基本的 RGB 图像开始 然后我们要对它 应用一些效果 假设我们想做洗掉的小丑白妆 我要对它做一些调整 然而 这些调整 适用于整个图像 所以我们希望这些只局限于 皮肤区域 所以 我们要使用皮肤抠像 然后我们要把这三幅图 结合起来得到 我们想要的结果
我来给大家介绍一下它的代码 因为它实际上很简单
但首先 我想谈谈 我们对核心图像的 首要特性要求 这是为了让人们更容易地 发现和使用我们现有的 200 多个 内置滤镜 这就是新的头 名为 CoreImage.CIFilterBuiltins 这些允许你使用所有 内置的滤镜而不需要 记住滤镜的名字 或输入的名字 所以 真的很棒 让我展示一些 使用这个新头的代码 我们要做的第一件事 是创建基础图像 我们只需要调用 带有 URL 内容的图像 这将产生 传统的 RGB 图像 现在 我们要开始 应用一些效果 首先我想要 把它转换成灰度图 我要用一个叫 maximum component 的滤镜 我要给这个滤镜 一个基础图像的 输入图像 然后我要求 那个滤镜输出 它会产生一个 像这样的灰度图像
这看起来不够鲜艳 不像小丑妆 我们要再应用一个附加滤镜 我们要声明使用 gamma adjustment 滤镜 这个的输入将是 之前滤镜的输出 然后我们要指定 伽马函数的幂 然后请求输出图像 你会注意到现在 很容易指定 伽马滤镜的幂 它是一个浮点型数 而不需要记住使用 NS 数字
这是我们效果的第一部分 接下来我们要做的 是得到皮肤分割抠像 正如我之前描述的 我们将从一个 URL 开始指定 我们想要的皮肤抠像 然而 当我们得到这张图片时 你会注意到它比另一张小 如前所述 默认情况下这些是一半尺寸
我们需要把它放大以匹配 主图像的尺寸 我们要创建一个 CGAffineTransform 它可以把抠图尺寸缩放到基本图像尺寸 然后我们要 对图像进行变换 这就产生了一个新的图像 正如你所期望的 它匹配了正确的尺寸
下一步我们要做的是 把这两个结合起来 我们将使用 blendWithMask 滤镜 这很棒 在我刚展示的例子中 我们一直在用这个
我们将背景图像 指定为基本 RGB 图像 它看起来就像这样 接下来 我们将指定 输入图像 这将是前景图像 它是 应用了白色化妆的图像 最后我们要指定一个 蒙版图像 也就是我之前展示的图像 根据这三个输入 你可以向混合滤镜请求它的输出 结果是这样的 现在 正如你所看到的 这只是一个起点 你可以将各种有趣的 效果组合在一起 从而在你的 App 中 产生很棒的效果
一旦应用了这些效果 你就需要保存它们 最典型的情况是 你希望将它们保存为 HEIF 或 JPEG 文件 这也支持保存 辅助图像 因此 除了主图像 你还可以存储 语义分割抠像 以便你的 App 或其他 App 可以应用 附加的效果
其代码非常简单 使用这个核心图像 API writeHEIFRepresentation 通常你指定主图像 和你想要保存它的 URL 然后是你想要保存的像素格式 以及你想要保存的颜色空间 今天我想强调的是 另一组选项 你可以在保存图像时提供 因此 例如 你可以指定 关键的语义分割皮肤抠像 并指定皮肤图像 头发图像或牙齿图像 所有这四幅图像 都将保存到生成的 HEIF 或 JPEG 文件中
现在有另一种获得 这个结果的方法 如果你想 你可以保存一个 主图像并指定 分割抠像作为 AVSemanticSegmentationMatte 对象 同样 这个 API 非常简单 你可以指定 URL 主图像 像素格式和颜色空间 在本例中如果你想要 指定这些对象 保存在文件中 你只需声明 AVSemanticSegmentationMattes 然后提供一个抠像阵列
所以 这就是使用核心图像 和这些抠像所能做的 我今天讲的是 如何为抠像创建图像 如何应用滤镜 以及如何保存它们 不过 我要提一下 我向你们展示的示例 App 是作为一个照片 App 插件编写的 如果你想了解 在你的 App 中怎么做 才能让你 保存这些图片不仅为 HEIF 格式 还在用户的照片库中 我建议你查看 那些早期的演讲 尤其是从 2014 年的 WWDC 关于照片框架的介绍 好的 非常感谢大家 我非常期待看到 你们使用这些出色的特性 谢谢 [掌声]
-
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。