大多数浏览器和
Developer App 均支持流媒体播放。
-
在 iPhone 摄影中获取景深
iPhone 7 Plus 上的人像模式展现了摄影中景深的力量。在 iOS 11 中,您的 app 现在也可以使用驱动这项功能的景深数据。了解如何利用景深来为创意图像带来新的可能。更深刻地理解高级景深概念,并学习如何从相机获取流媒体和静态图像景深数据。
资源
相关视频
WWDC23
WWDC19
WWDC17
-
下载
(关于iPhone摄影中的 深度捕捉)
欢迎来到演讲507 我叫布莱德·福德 我来自相机软件团队 我很激动 能在今天下午和你们 分享一些深入的看法
看到我要做什么了吗?好了
本次演讲 是两个演讲的第一部分 这两个演讲会介绍Apple 今年发布的一个非常重要的新功能 那就是包含深度信息的多媒体内容 我会从概念层面上介绍一下景深 我会带着你们熟悉一些关键的术语 我会教你们如何在iPhone上 捕捉深度数据 就像是这张照片 你会在本次演讲中看到 许多幽灵般的图片
我们的计划是这样的
首先我们会介绍深度和视差 它们出现在iPhone 7 Plus上 我会从大体上介绍一下 接着我们会介绍下如何从 相机获取流式的深度数据
拍摄带有深度数据的照片 最后我们会介绍一个有点离题的主题 也就是双照片拍摄 这是请求最多的 关于双摄像头的功能 我很激动能介绍一下它 你要做的就是听一下所有这些 很糟糕的深度双关语 我会不断在本次演讲中 介绍关于深度的内容 让我们一起做个游戏吧 好吗? 每当你听到一个关于深度的双关语时 就给我点抱怨声 这样我就知道你们在专心听了 好吗? 让我们试一下 大家准备好深潜了吗?
谢谢 我从心底感谢大家
好了
你们今天之所以来这里都是因为它 这就是iPhone 7 Plus 这个产品卖得 甚至比上代plus更好 这在很大程度上要归功于 高质量的双摄像头系统
它是一个双主镜头系统 由一个28毫米的广角摄像头 和一个56毫米的 长焦摄像头组成 它们都是1200万像素的 它们共享同样的功能项 和相同的格式 你可以独立运行其中的一个摄像头 或是利用一个虚拟的第三个摄像头 来一起使用这两个摄像头 这是我们首次将这项技术 运用在iOS上 我们把它叫作双摄像头 它以同步的方式 以及相同的帧率运行双摄像头 并且通过共同运行双摄像头 来实现两个选框功能
第一个功能是双摄像头变焦 它会在广角和长焦之间进行自动切换 当你在变焦的时候 它会适配曝光 对焦 还有帧率 这挺神奇的 你甚至意识不到我们切换了摄像头 但所有这些事件都无缝地发生了 我们还会视差偏移进行了补偿 使其能够平滑地过渡 当你来回在 广角和长焦之间进行切换时
第二个选框功能 当然就是人像模式了 也就是双摄像头系统锁定在 长焦摄像头的窄视野上
但会同时使用广角和长焦的图像 来生成一幅漂亮的浅景深效果的图像 通常你要用一个贵得多的照相机 带有快速 广角的镜头 才能实现如此效果
前景在聚焦时看起来很锐利 而背景会逐渐变得模糊 像是这些好看的小花束圈
景深效果甚至在iOS 11中 变得更棒 我们还针对渲染失焦的区域进行了改进 这样可以更准确地表现一个 高度自由的快速镜头 还带有锐利清晰可辨的花束圈 我们还改进了对边缘进行渲染的方法 也就是前景和背景之间的边缘 如果你不清楚的话请去看一下 我估计你会很惊讶地发现 这是多么棒的 浅景深效果 被呈现于iOS 11
要生成 这样的效果你需要区分 前景和背景 换句话说 你需要用到深度 截至目前 深度信息 只包含于 Apple相机应用的人像模式中
不过现在iOS 11中 我们向第三方应用开放了深度信息
这里是一个灰度可视化的深度图 它被嵌入到这个图片文件里
有了深度信息就拥有了 更多编辑图像的可能性 像是将不同的滤镜应用到背景和前景中 就像是这样
这里我将一个黑白滤镜应用到背景 还将一个淡入淡出滤镜应用到前景 你就能发现 这小女孩 的裤子还是粉色的 但是裤子后面的物体都是黑白的了 了解了深度的渐变 我就能 实现更加复杂的功能 将转换点 像这样前后移动 这样就能让你的注意力集中在花上面
注意下 只有她的手还有手中的花是有颜色的 而其他的物体都是黑白的
你甚至可以对前景和背景的曝光 进行不同地控制 像是这样
她现在看起来就像是被 photoshop到了她自己的照片上 我不是说你非得这么做 我的意思是你可以这么做
好了 闲话少叙 让我们讲点技术性东西 我想把这部分叫作 深度学习 (深度学习) 谢谢你们 首先我们需要定义一下什么是深度图 在现实世界中 深度指的是 你与被观察对象之间的距离 而深度图就是将一个三维场景转换 成二维场景的表现形式 你可以通过将深度设定为一个 恒定距离来实现 我来解释下我说的是什么意思 我会用到一个针孔相机的图 它被用来说明此类问题 如果你研究过计算机视觉 你就会对针孔相机非常熟悉 针孔照相机其实就是 一个没有镜头的简易遮光盒 它只有一个小的孔洞 一个能让光进入的小孔 并将自己以一个倒转的图像投射到 像平面的另一边或者是传感器上 (深度图) 另一边也叫作像平面或是传感器
而这个光线所通过的孔 被称为焦点 而所拍摄图像的视野 取决于焦距 焦距就是从焦点到像平面的距离 较短的焦距就意味着更宽的视野 而较长的焦距 还有较长的盒子 就意味着更窄的视野 焦距就是一个恒定距离 它将现实世界的距离扁平化 成一个2D图像 简单来说 深度图就是 将一幅3D深度图像转换为 2D的单通道图像 其中每个像素值都有不同的深度 像是5米 4米 3米
为了测量深度 你需要一个专用的摄像头 就像是一个渡越时间摄像头 例如 有一个从物体反射光信号系统 接着它能测量其返回传感器的时间 iPhone 7的双摄像头不是 渡越时间摄像头 它是一个基于视差的系统 视差是一种用来测量 物体偏移量的量度 当你从两个不同镜头观察物体时 像是从你的眼球观察 Disparity就是视差的别称 你只要稳定住头 就可以观察到这个效果 将你的目光固定在近处的某个物体上 然后就不要再移动头了 先闭上一只眼 然后再闭上另一只 比方说 就是 左眼 右眼 左眼 右眼 这时候你就可以发现 有颜色的铅笔看起来偏移得 比后面的记号笔要多 因为它们离得更近 这就是视差效果 或者disparity
现在接着回来介绍针孔相机模型 我拍摄一幅鸟瞰图 是由两个立体纠正相机所拍摄的 也就是说 第一 它们是彼此平行的 它们指向同一个方向 第二 它们有相同的焦距 这是非常重要的 那就是从焦点到像平面或是 传感器的距离 每个摄像头都有一个测量好的 光学中心或者说主要点 如果你画一条从针孔到像平面的垂直线 那么光学中心就是它 与像平面相交的点 另外还有一个你应该熟悉的术语 那就是基线 基线指的是 两个镜头的光学中心之间的距离 是在立体纠正系统里的两个镜头 它是这么工作的 来自一个被观察对象的光线 穿过光学中心 或是通过孔径 并且落在两个摄像头 像平面的不同点上
我想要给你们讲的第四个术语是Z Z是用于深度 或者说现实世界深度的规范术语
现在看看像平面上的点会怎么样吧 随着被观察的点距离变得更远
像平面上的点离得更近了 我会给你们再展示一次
随着现实点离得更远 它们在像平面上离得更近了 而随着对象离得更近 像平面上的点会互相离得更远 所以当使用立体纠正摄像头的时候 这些偏移只会朝着一个方向移动 它们要么互相离得更近 要么离得更远 但它们都位于一条线 或是极线上
在了解了基线后你就 可以排列你的相机 像是这样沿着它们的光学中心 接着减去像平面上被观察点之间的距离 就可以获得视差 这就是视差 你可以将这个距离以任何单位表示 只要对你的处理过程有帮助就行 它可以是像素 米 微米 通常我们会以像素为单位保存它 因为RGB图像是以像素表示的 我们就可以正常保存像素偏移了 只要它们对应的图像没有改变 大小就可以 你最好不要编辑这个图像 因为如果你缩小了这个图像 你就会同时改变像素的大小 你就得检查整个图 然后缩放深度图中的每个值 这是一个非常不友好的实现方式
我们Apple 选择使用标准化的值来表达视差 这些值对于缩放操作是有弹性的 我们是这么实现的 再回到我们的被观察点 你就会发现两个相似三角形 我来给你们着重标出 (消除视差) 这些三角形具有 相同比例的边和定理
如果我抹掉相机 只给你们显示这些三角形 现实世界三角形的边就是Z 或是米 以及基线 也就是两个 光学中心之间的距离
在这个光盒 或者说遮光盒里
同一个三角形会被表示为 以像素为单位的焦距 和以像素为单位的视差 你们感觉要开始讲数学了吗? 我感觉到了 请听我接着说 这没什么可头疼的 基线 比上以像素为单位的Z
就等于 视差比上焦距的长度 如果我们将两边都除以基线的话 左边的b就会被消去 而左边留下的就是1比上z 这很不错 1比z就是深度的倒数 视差差不多就是这个意思 当某个物体向远处移动的时候 视差会缩小 而当它向近处移动时 视差就会增长 所以说它就是深度的反函数
而我们把右边所剩下的部分 称为规范化视差 它不再是像素偏移了 而是d比上焦点距离乘以基线 基线就被内置了 所以你不需要再单独携带此信息了 当你 处理深度图的时候 视差的单位是1/米 就像是1比上z 它可以处理缩放操作 如你所见 将深度转换为视差是很简单的 因为它只用1除以什么 这样的操作就能完成
有人觉得超出接受范围了么?
(视差对比深度) 它听起来挺麻烦的 不过总结起来很简单
我们有一个基于视差的系统 而不是一个真正的渡越时间相机 不过视差是个不错的深度代理 而且规范化的视差就是深度的倒数
(沉思) 提到规范化视差 也就是深度的倒数 这里我们好好想一下
这幅图片有一个视差图
我觉得这就是一个反深度的跳跃
谢谢你们 可以了 我们在深度API集中使用了 深度数据这个术语 这是个用来表示任何 有深度物体的专业术语 它可以指代一个真正的深度图 或者是一个视差图 它们都是与深度相关的 它们都是有深度的 因此它们都是深度数据
而且我们专门给它创建了一个对象 根据我们平台上对于深度的定义 其权威表示 被称为AVDepthData 它能被用于iOS macOS 以及tvOS上 这是AVFoundation框架上的一个类 它可以表示深度图 或是视差图 它还提供一些不错的功能来转化 深度和视差 让我们来看看 深度图的细节吧 深度图就是一些图像 如果你现在还没看明白的话 它们有点像RGB图像 但它们是单通道的 不过它们仍然能被表示成 CV像素缓冲区 而现在CoreVideo定义了 四种新的像素格式 给那些我们在前面的幻灯片 看到过的类型使用 它们都是浮点型的 头两种格式是用于规范化视差的 它被表示成1/米的形式 注意下有16位 和32位两种形式可选 后两种格式是用于深度的 它们用米来表示 它们也是有16位或者32位可选的 我们为何要这么做? 如果你想要在GPU上对深度进行处理 你就应该请求16位 或者说半浮点的深度值 如果你是在CPU上进行处理 你就应该使用全32位的浮点变量 它们更加合适
我们会在后面介绍下 AVDepthData对象 是从何而来的 不过现在让我们 只关注一下它的核心属性就好 有了AVDepthData对象 你就可以查询它的深度数据类型 也就是四种像素格式之一 你可以访问 depthDataMap本身 它是个CV像素缓存 你能以 行和列来遍历它 利用标准CV像素缓存API (引入AVDEPTHDATA) 而最后两种我想在这里着重说明 它们跟捕捉深度数据的内在问题有关 我们会一个个地说明这些问题 并且讨论下解决办法
第一个问题是洞 深度数据上的洞 为了计算视差 两个相机都需要观察 同一个点 不过是从两个不同的角度 如果它们观测不到这个点 就不会有视差 为什么它们可能看不到这个点呢?
首先可能是堵塞问题 比如说 有根手指伸了进来 突然挡住了你的其中一个相机 如果它变得有点模糊了 或者完全模糊了 你就不能再看到两个点了 因此你就没有视差了
另一个更常见的原因就是 很难找到特征 当相机一和相机二 的图像被比较时 你应该记得 两个相机通过光学中心 将它们进行排列 并且寻找某些特征 这些特征是匹配关键点的 假如说变暗了 那么被观察点可能就没有 清晰可辨的特征了 颜色变得有点嘈杂 并且很难发现边缘 另一个例子就是 如果你将照相机指向一面 平的没有纹理的白墙 墙上基本上没有特征 因此就很难找到 用来匹配的不同之处 无论是以上哪一个原因 你的图像中都可能有某些区域 是根本找不到视差的 而这就被称为洞
洞在深度数据图中被表示为非数字 标准的浮点表示形式 要么是16位 要么是32位的 深度图可能也会被处理来填补这些洞 我们可以通过基于周围深度数据的 内插来实现 这么做很不错 或是通过使用RGB图像中 的元数据来实现 isDepthDataFiltered属性 是AVDepthData里面的属性 它会告诉你是不是用这种方式 来处理图的 若你接收到了一个未过滤的 AVDepthData 你在这个图中应该只能找到非数字的值
我们一会儿再介绍如何请求过滤的内容
第二个牵涉到准确视差生成的问题就是 校准错误 有许多校准错误 是我们可以修正的 不过有一种是我们不能修正的 那就是计算错误的光学中心 不管是两个摄像头中的哪一个出了问题 这里我是将针孔相机 向下偏移了90度 这样就可以在顶部留下更多的空间 在一个理想的立体纠正系统中 远景只会在一个方向上偏移 向左或是向右 随着这些相同的线 如果有条光线是从相机一观察到的 它就可以被看成是 一条来自相机二线上的 一系列相交点 (校准错误) (相机1 相机2) 要精确地测量视差 你必须要有一条精确的基线 基线也就是两个光学中心之间的距离 如果你没有精确的基线 你就不能对齐两个相机的光学中心 那么你就不能知道有多少的视差了
那如果光学中心被算错了或者 报错了会怎么样呢? 假如说真正的光学中心在这 但是因为某些原因 它被错误地报告成这里 突然间我们相机二像平面上的 所有视差点 都向左偏移了相同的固定数值 现在所有的对象 都会被比它们的真实位置报告得更远些 如果错误是发生在反方向的话 这些物体 就会被错误地报告为离得太近了 我们可以探测到并修复许多问题 但这个问题是我们不能探测并且修复的 因为所有这些点看上去 是在同一条正确的线上 我们区分不出来是基线有问题 还是人移动得更远或是更近了
这是怎么发生的呢 为什么 光学中心的计算会出问题呢? 因为iPhone的摄像头 用的不是针孔 它们用的是透镜 而且iPhone上的透镜不是固定不动的 如果使用了OIS 那么透镜可能会横向移动 来抵消手的抖动
重力也会发挥作用 因为它会导致镜头下垂 聚焦致动器实际上 就是施加了电流的弹簧 所有这些原因都可能会 导致它横向移动一小点 而这些光学中心位置的细微的错误 会导致视差的巨大错误 当发生这种情况时 结果就是一个恒定量的错误会出现在 图中的每个像素点上
视差值相对于彼此仍然是可用的 但是它们不能再反映现实世界的距离了
出于这个原因 AVDepthData对象 必须有一个精确的概念 绝对的精度值意味着单位 确实能反映现实世界的距离 并没有校准的问题 相对精度意味着 Z排列仍然被保留着 但是现实世界的比例已经丢失了 对于从第三方相机捕捉的深度数据 它可以被报告为绝对或是相对的 但是iPhone 7 Plus 总是会报告相对精度 这是因为我刚才提到过的校准错误 但是我不想让你们被它吓到 相对精度其实并不糟糕 双摄像头的深度其实是完全够用的 让我来给你展示下为什么这么说
棒极了 幻灯片上有些公式 这里又有一些数学的问题 比如 在左边我们有个相对精度的视差值 也就是那个上面带有一个小帽子符号的 字母d 因为它不是很好 它等同于 一个绝对视差d 加上一个固定量的错误 我们不知道固定量的错误是多少 但是它就在那
现在让我们进行一个常见的操作 比如寻找 同一个图中两个视差的不同之处 这就像是减去不同的部分 比方说 等式看起来是这样的 这里你有两个不好的数据 你要减去两个不好的视差 这就如同两个好的视差有着 同样的固定错误 如果我们把它们重新排列 就会发现 我们实际上解决了这些错误 因为它们相互抵消了 而我们剩下的 就是一个令人开心的巧合
这个令人开心的发现就是 不同处是一样的 不管你的视差是 绝对的还是相对的 这个公式在某种程度上证明了 相对就像绝对的一样好 如果你要实现的效果只依赖于 相同图中的不同之处的话 这就是为什么 通过相对精度深度所生成的效果 看起来仍然很棒
介绍完这个我觉得我们已经讲完了 AVDepthData的有关内容 或者说我们已经差不多结束了
是时候接着讲我们 的第一个拍摄专题了 也就是流式深度 我觉得这时候应该做个演示
我们要做的演示叫 AVCamPhotoFilter 这个应用是我们去年 作为示例代码所发布的 它会为你们展示如何将一个效果 如何实时地将一个效果应用到预览中 并且将同样的效果渲染到照片上 去年它只有顶部的一个按钮 它是用来过滤视频的 它会将一个 有些劣质的玫瑰色 显示效果应用到这个视频上 不过它还是实时为你呈现了预览 并且它还在你拍照的时候 将其渲染到了照片上 今年我们将一些深度加到了这个示例中 借以向你们展示下 如何以流的方式来预览深度 现在我们要做的就是 打开深度 并且通过混合 完全RGB和完全深度来预览 (深度) 我要把我可爱的助手凡娜叫上来 其实他叫埃瑞克 谢谢你 埃瑞克 他会上来给我们展示 一些动态的东西 像是一个棒球手套 我很喜欢它 需要注意的是 还有很多的跳动 你肯定是能看到镜头里是什么 不过这样并不是很完美 有许多临时的问题 不过我可以点击下Smooth按钮 我们马上就过滤了 深度 填补了洞 暂时使它们变得平滑了 现在 这就是个看起来不错的视差了 我要拍一张照片
如果我现在回到照片应用中 就能找到我们刚刚拍摄这张 非常不错的深度展示 现在这就是个有启发性的应用了 因为我们终于能回答这个问题了: 你的手套 你的手套有多深呢? 你们真的要学会啊 好的 让我们回到幻灯片上 (关于AVCAMPHOTOFILTER 的演示)
我知道已经很晚了 我想让你们保持清醒
我们是如何实现的呢
AVFoundation框架的 相机捕捉类 分为三个主要部分 第一个是AVCaptureSession 它就是一个控制对象 你可以让它开始或停止运行 但是它不能实现其他功能了 除非你给它某些输入 这里我们有一些AV捕捉输入 例如AVCaptureDeviceInput 这里我已经创建了一个 跟双摄像头相关的了 它会给这个会话提供输入 不过现在你需要将其 作为输出导出到某个地方 现在我们就有了一种新的输出 叫作 AVCaptureDepthDataOutput 它在我们的团队中 被简称为DDO 它的功能类似于 VideoDataOutput 除了VideoDataOutput是向 CoreMedia提供示例缓冲区 而它提供的是 AVDepthData对象 也就是我刚才讲过的 那个权威的表示形式 它以流的形式将它们送达 (引入AVCAPTUREDEPTHDATAOUTPUT)
AVCaptureDepthDataOutput 都支持什么呢? 你当然可以将它添加到 任何会话的任意位置 不过这样你得不到深度 除非你是在双摄像头模式下 因为这是唯一的双系统 或者说立体系统 是我们用来计算视差的
当你将一个DepthDataOutput 附到你的会话中时 会发生一些事情 双摄像头会自动地放大到2倍 也就是长焦的全部视野 这是因为为了计算视差 焦距必须相同 而在2倍变焦下 广角与长焦摄像头的焦距是一致的
与此同时 当你计算深度的时候 缩放是被禁用的 我们添加了 一些新的访问器 到AVCaptureDevice中 在双摄像头系统中 你可以查到哪些视频格式是支持深度的 通过查询supported DepthDataFormats就可以找到
还有一个新的属性叫作 activeDepthDataFormat 它可以让你明白 activeDepthDataFormat是什么 或是选择一个新的 DepthDataFormat
目前我们支持 三种深度的视频分辨率 或者说深度的预设 让我来一个个介绍下 第一个是广受欢迎的 照片预设 在照片预设中 你可以获得一个 屏幕尺寸的预览 该预览来自于VideoDataOutput 你还能获得一张1200万像素的完整图像 其来自于photoOutput 这里你可以发现VideoDataOutput 提供的是1440x1080分辨率 也就是屏幕尺寸的图像 除此之外 如果你使用了 DepthDataOutput 你就可以得到一个320x240 最大帧率为24fps的深度数据 为什么这么小呢? 因为你需要消耗很多性能 才能处理每秒24帧的视差图 如果你愿意的话 你可以获得一个较低分辨率 只有160x120的视差图 第二个是16x9格式 这是今年的一个新格式 去年我们引入了一个720p 帧率高达60fps的16x9格式 该新格式最高能支持30fps的帧率 但是它支持深度 它也支持 DepthDataOutput 以320x180或是 160x90的分辨率 最后 我们有个非常小的 VGA大小的预设 或者说活动格式 如果你想要个非常小而且快的视差图 就可以使用它
让我们来谈下帧率 AVCaptureDevice能让你设置 最小和最大视频帧率 但是它不允许你 设定深度帧率 独立于视频的帧率 这是因为深度需要 与视频帧率保持一致 或者说保持在同等分割的 视频帧率上 比如说 如果你选择的最大视频帧率为24 深度能跟得上视频的最大帧率 那么你就可以得到24fps的深度 但是如果你选择的是30fps的视频 深度就跟不上了 所以它就不会选择24 而是15 这样就能得到 更容易被划分的部分了
(AVCaptureDepthDataOutput 的深度过滤) DepthDataOutput支持 过滤深度数据 就像是我刚才在 AVCamPhotoFilter演示中所说的那样 这样就可以填满洞 还可以使其变得更为平滑 随着你的移动 这样你就看不到 帧与帧之间短暂的跳跃了
好了 让我们来看下目前的 四种数据输出 我们现有四种了 第一种是VideoDataOutput 它在iOS 4中就已经出现了 它会一个接一个地将视频帧 以30fps或是60fps的流媒体方式 根据你所设定的数值送达给你 还有一种是 AudioDataOutput 它通常一次会以44.1的速度 向你推送1024个PCM帧
我们还有MetadataOutput 它可以提供 面部 检测到的面部 或是条形码 这些都会偶尔出现 它们在寻找面部信息的时候 可能会有最高4帧的延迟 我们新添加了 DepthDataOutput 也就是我刚刚提过的 它会以视频的帧率送达 或是以视频可整除的帧率来送达 这样就变得有点荒谬了 要处理所有这些数据输出 你必须要有一个非常成熟的缓冲机制 来追踪所有进来的对象 如果你要同时处理所有这些数据 或是一并处理某个特定的表现时间 我们发现这个问题已经有一阵子了 但是DepthDataOutput 证明它就是解决问题的桥梁
掌声不是很响亮呀 下次请拍得更响一点 在iOS 11中 我们添加了一个 新的同步对象 叫作 AVCaptureDataOutputSynchronizer 它可以在给定的呈现时间内 送达所有的可用数据 在单个统一的回调函数中 它会提供一个集合对象叫作 AVCaptureSynchronized DataCollection 它能让你指定一个主输出 也就是对你来说最重要的输出 你想将所有其他东西 都同步到主输出上 然后它就会保留所有多媒体信息 只要你需要的话 以确保所有的数据 在给定的呈现时间内都是可用的 在它给出单个统一 回调函数之前 它要么会给你所有输出的数据 要么就是能确保 如果没有特定输出的数据的话 它就会给你提供一个与它有关的集合
这里有一个代码段 它给你们展示了数据输出同步器的 统一代理回调函数是如何工作的 该回调函数会传给你一个 SynchronizedDataCollection 这很酷 你可以像使用数组一样来使用它 或者是像词典那样使用 取决于你想用它实现什么功能 你可以像是遍历数组一样遍历它 你可以使用快速枚举来获取 当前集合中所有对象的列表 或者说如果你想将它 当成词典那样使用的话 你就可以通过索引数据输出的下标 来得到你想要的结果 例如 我这里只想查找某个特定的结果 该结果来自于DepthDataOutput 要是结果存在的话 它就会把结果给你 你需要在代码中 用到guard语句来查找nil 因为你可能在给定的呈现时间内 找不到任何深度数据
好了 这里举个如何使用AVCaptureData OutputSynchronizer的例子 这里又用到了AVCamPhotoFilter 该示例代码已经可以供你们查阅了 它被关联到这个演讲中了 你现在就可以下载它
在iOS 11中 有另一个新的流式功能 它有点偏离今天的主题 那就是对于每个视频帧的 相机内在功能送达的支持 当你在使用 VideoDataOutput的时候 回忆下我们前面讲到的针孔相机 它可以将3D空间中的点 转换成2D空间的 我们需要两种信息 我们需要光学中心 或者说主点 我们还需要焦距 在计算机视觉中 你可以使用这些属性 来将2D图像重新投影回3D空间 通过使用逆转换 这也是新的ARKit的重点 作为iOS 11中的新功能 你可以选择接收一组内在函数 此函数适用于你所送达的每个视频帧 并且你可以通过调用 AVCaptureConnection的 isCameraIntrinsicMatrixDelivery Enabled方法来选择 当你这么做的时候就可以 在每个缓冲区都获得一个附件 该附件包含内在功能 让我展示矩阵本身是什么样子的 它可能看上去挺复杂的 其实相当简单 相机内在函数是一个3x3的矩阵 它描述了相机的几何属性 fx和fy是以像素表示的焦距 它们是单独的x和y值 因为有时候相机 具有变形镜头或者变形像素 在iOS设备上 我们的相机 一直都使用方形的像素 所以fx和fy总是相等的
x0和y0是两个像素坐标 它们是镜头主点 或者说光学中心的坐标 它们都是以像素为单位表示的数值 而且它们都是根据 提供它们的视频缓冲区的 分辨率所给出的 所以一旦你选择了 就能以流的方式获得样本缓冲区 而且你会从它们那得到这个附件 其有效载荷是一个C/F数据 它包含了一个3x3的浮点数矩阵 也就是SIMD数据类型 如果你在做计算机视觉相关的工作 你就会对这个新功能非常感兴趣
好了 我们已经正式讲完了关于流的专题
这次不错 接下来让我们介绍下照片的拍摄 让我们从演示开始吧 AVCam 和WIGGLE ME
这里有两个内容要讲 我们这里要介绍两个应用 AVCam是示例代码的重要部分 它会展示如何 使用AVFoundation 来拍摄照片和影片
这里要注意的是 尽管我们已经 对其添加了深度的支持 你还是看不到任何与深度有关的东西 这是因为当我拍摄这里的铅笔时 你实际上是看不到深度的表现的 但是它已经被保存在照片中了 所以当我进入相机应用后
让我来看一下 比方说 我进入了编辑菜单 上面弹出了什么 顶端出现了一个Depth按钮 现在如果我点击Depth按钮 它马上将会将一个模糊特效 应用到背景当中 这真的很酷 所以现在你在应用中 拍摄的照片 也可以使用这个浅深度域的效果了 这真的很酷 我们还可以利用深度 实现更多有意思的功能 既然现在所有的照片都有深度数据了 另外 在iOS 11中 所有你以 人像模式拍摄的照片现在 都保存了深度信息 它们就是你 新的创意应用的素材 我要用这个叫作 Wiggle Me的应用 来展示一些 你可以利用深度实现的创新功能
我挑个简单的开始讲 此功能实现的是将一些平面的东西 重新投影到3D空间 使其看起来有点滚动的效果 我可以让它停止滚动 我还可以使用陀螺仪来移动我的手机
这难道不是精妙的效果吗? 它看起来栩栩如生的 我想再挑个功能来讲讲
我真的很喜欢这只狗 这只狗看上去很不错 现在他看上去就在 左右地移动了 你还可以 强制让透视发生变化 在知道了 深度数据在哪里之后 你就可以利用深度实现这样的功能了
放大吧多利
放大吧多利 挑衅吧狗狗 我希望在多利放大的时候 将其进行旋转 因为它有点像是条黑帮狗
我觉得最适合这里的音乐 应该就是“Rolling in the Deep”了 不是吗?
你们做得很好 我很感谢 我真的很感谢
在拍摄带有深度的照片时 我们提供了很多的拍摄选项 你可以使用深度进行带闪光灯的拍摄 你可以使用深度进行静态图像防抖 你甚至可以实现自动包围曝光 比如a+2 -2 0 EV 你可以利用保存在照片中的深度数据 来制作Live Photos
你可以使用AVCapturePhotoOutput 来获取带有深度的照片 这个类是我们去年引入的 将其作为 AVCaptureStillImageOutput 的继承者 它可以非常出色地处理复杂的照片请求 我所说的是可以获得多个资源的请求 而这些资源是必须被追踪和送达 比如说你想获得一个raw图片 JPEG图片 或者live photo影片 等等 你会在不同的时间点得到很多东西 这里的编程模型要你填写一个请求 该请求叫作 AVCapturePhotoSettings 你通过传递请求来开始照片的拍摄 你还要传递稍后会被调用的代理 因为你的photoOutput是 唯一用来拍摄Live Photo 裸RAW图像 和Apple P3宽色图像的接口 它还是iOS 11中唯一可以 拍摄HEIF文件格式的方法 这在Keynote演讲中提到过
你需要对 AVCapturePhotoOutput进行许多修改 这样才能支持HEIF 所以在iOS 11中 为了适应如此多的变化 我们添加了一个新的代理回调函数
它很简单 它用来代替 你获取样本缓冲区的回调函数 现在你会得到一个叫作 AVCapturePhoto的新对象 AVCapturePhoto是 深度唯一的传递媒介 因此如果你想用深度的话 就得实现这个新的代理回调函数
另外 你需要 在会话开始前明确选择 DepthDataDelivery 为什么呢?如果你们还记得的话 双摄像头 在处理深度的时候 需要进行某些特殊的操作 它需要放大到2倍 使焦距匹配 它需要锁定变焦功能 这样你就不能再进行缩放了 想要实现这个功能 在开始运行会话之前 你就需要告诉photoOutput “我需要DepthDataDeliveryEnabled” 然后根据每张照片的请求 也就是在你 拍照的时候 你就会填写一个设置对象 “我想在这张照片中包含深度”
然后你就可以使用返回的 AVCapturePhoto了 它有一个叫作 AVDepthData的访问器 哇 这个AVDepthData 真的是无处不在啊 它就像是深入集成到了API中
iOS上绝大多数的 AVCaptureDevice 格式都具有 更高的静态分辨率 比起流式方案来说 看下我们 在iPhone 7 Plus上 支持深度的格式 你就可以发现流式视频分辨率 可以和你获得的高分辨率照片相媲美 例如 对于照片来说 如果你使用流的话 你只能得到屏幕大小的缓冲区 但你可得到1200万像素的静态照片 对于深度也是这样
我说过当我们在用流处理深度数据时 有很多需要实时完成的工作 以满足24 fps的要求 但是当处理照片的时候 我们还可以有一点额外的时间 因为它不需要实时送达 所以我们可以就可以给你 提供一个非常高质量 好看的图 它的分辨率是流分辨率的两倍之多
其长宽比总是与视频的长宽比保持一致 如果你处理的是16x9的视频 你就会得到16x9的图
好了 现在是时候谈一下关于失真的话题了 我们捕捉并且嵌入到照片中的深度图 是失真的 我很抱歉给你们带来这个消息 不过这其实是个好事 让我来解释下为什么 所有我给你们展示过的相机图 都是针孔相机的 针孔相机没有镜头 所以图像就是直线的 也就是说 光会以直线形式穿过小孔 并且呈现一个几何完美的 复制倒置物体在像平面上 如果你有这样一个完美的正方形网格 并且用针孔相机给它拍了张照片的话 它在像平面上看起来就是这样的 不过是上下颠倒的 直线会一直保持直的
不幸的是 在现实世界中 我们需要让更多的光线进入 所以我们需要镜头 而镜头是有径向失真的 这些失真也会存在于所拍摄的图像中 因为它们会以 有点奇怪的方式弯曲 这样它们才能到达图像传感器 在一种极端情况下 由一个坏镜头所捕获的直线 可能看起来是这样的 这样不利于寻找视差 因为两个图像需要匹配得上 才能找到特征 如果相机一有一组失真 而相机二有一组不同的失真 你要如何才能 在这两个图像找到相同的特征 因为它们失真的地方不一样呢?
我在描述如何计算视差的时候 落下了一个重要的步骤 我现在就把它补充一下 在比较长焦和广角图像之前 我们还需要做一件事 我们要让这些失真的图像直线化 也就是说 我们要利用一组校准系数 来使它们不再失真 这些系数代表了镜头的失真标准
在每个图像都被修正后 看起来就是这样的 令人满意的 笔直的直线 我们现在就可以确定地 比较两个图像中的点了 并且能够找到一个完美的 现实世界的 直线的视差图 看起来就像是这样
我们有了一个完全相反的问题 视差图匹配了物理世界 但是它跟我们刚刚拍摄的图像并不匹配 也就是由于镜头而变得失真的图像 所以现在我们要完成另外一个步骤 就是要将视差图通过失真 重新变回图像原有的样子 我们要使用一组 逆透镜系数来实现这一点 这样最终的视差图 就会有相同的几何失真了 跟它对应的图像一样
要我说的话 这是个好事 让我来解释下为什么 这就意味着我们有了开箱即用的 深度图 它的图片 特别适合使用滤镜 和进行特效处理 它们总是与相关的图像匹配 如果你想要实现某种特效 如果你想实现一些 像是Wiggle Me应用那样的效果 或是想让照片实现一些有趣的效果 就像是我最开始时所展示的那样 它们就能完美实现这一点 但它们不适用于重建3D场景 如果你想实现该功能 你应该把它们直线化 你是可以做到的 我马上就会介绍一下
我想要简单地介绍一下 我们图像文件中 深度数据的物理结构 在iOS 11中 我们支持两种 带有深度的图像 第一种是HEIF HEVC 这个新格式 也叫作HEIC文件 而它有着对于深度最好的支持 在此文件中有一个区域 叫作辅助图像 它可以保存视差 深度 或是透明度图 我们会把它保存在这里 我们将其编码为单色HEVC 我们还保存了一些 对于深度很重要的元数据 例如关于它是否被过滤的信息 它的精度 诸如镜头失真这样的相机校准信息 以及一些渲染指令 所有这些元数据 都跟辅助图像一起都被编码成XMP
我们支持的第二种格式是JPEG 虽然JPEG不是个很好的方法 但我们还是支持它了 如果是过滤的深度图 那么它就是8位的有损JPEG 而如果它里面包含了非数字 我们就使用16位的无损JPEG编码 来保存所有的非数字 我们会将它作为第二个图像 保存到JPEG的底部 它就像是一个多画面对象 如果你熟悉这个概念的话 我们同样将元数据保存为XMP 就像我们处理HEIF HEVC那样
好了 现在让我介绍下 双摄像头系统中呼声最高的开发者功能 它就是双照片拍摄
这是什么意思呢 到目前为止 当你使用双摄像头拍照的时候 你还是只能得到一张照片 它或者是用广角拍摄的 或者是用长焦拍摄的 取决于你缩放的倍数 你是处于1和2X之间的区域 你就会得到两者 的混合 我们会将其混合成一张更好的照片 但你还是只能获得一张照片 你们一直想要两张照片 现在我们就给你们这个功能 通过一个单一请求 你就可以获得广角和长焦的 全幅1200万像素照片 你能随心所欲 通过它们实现想要的功能
让我说下它是如何实现的 它和前面讲过的 对于深度的操作十分相似 在开始拍摄会话之前 你需要告诉photoOutput 我需要拍摄双照片 这样就能开启这个功能了 然后当你在拍摄基于 每张照片请求的照片时 你就可以完成你的设定了 比如说 我想将特定的照片拍成是双照片 给我广角和长焦的两张照片
当你这么做的时候 你所获得的照片回调函数的数量会翻倍 这并不是说你会得到两个回调函数 假如说你请求的是RAW 和HEIF的双照片 那么你就会得到四个回调函数 因为你会得到 两张广角和两张长焦的 RAW和HEIF照片 所以不管你之前得到多少个回调函数 现在数量会翻倍
现在我们支持了所有与深度相关的功能 你可以使用闪光灯来拍摄双照片 自动SIS 包围曝光 你还可以根据需要选择深度
我们是如何处理变焦的呢? 这里会出现安全性和信任的问题 假如说你的应用只显示长焦的视野 广角摄像头有更多的信息 所以在你拍照的时候 你实际上会拍到可视区域之外的内容 这就会产生隐私的问题 所以在你变焦的时候 我们会提供双照片 但是外围会变黑 这样它们就与预览中 所看到的视野一致了 如果你想要完整的图片 你可以将变焦设置成1倍 你怎么知道外面是否有变黑的区域呢? 在图片中我们保存了 一个纯净的孔径矩形 该矩形定义了有效像素的区域
双照片也可以通过相机校准数据送达 相机校准数据 可以用来实现 增强现实 虚拟现实 镜头失真修正等等 有了广角镜头 长焦镜头 和相机校准数据 你就可以制作自己的深度图了 我希望你们可以做出一个 比Apple更棒的深度图
你还可以实现增强现实 因为你获得了内在功能 让我来介绍下 相机校准当中的属性吧 这是我今晚要介绍的最后一个东西了 AVCameraCalibrationData 是我们相机校准的模型类 它在哪里出现呢? 如果你请求深度数据的话 你就可以同时得到AVDepthData 它是深度的一个属性
你也可以通过AVCapturePhoto 来获得它 你可以说我想对照片进行相机校准 就可以使用这个属性了 如果你要进行双照片拍摄 你就可以请求双照片 并且请求相机校准 这样你就可以获得两个照片的回调函数 并且你会获得广角效果的校准 以及长焦效果的校准了
intrinsicMatrix 看起来是什么样的呢? 我希望它能有点相似性 因为它差不多等同于我们之前见过的 流式 VideoDataOutput的例子 它也是一个3x3矩阵 并且包含了 CameraCalibrationData
它被用来从3D空间 转换到2D空间 当你要扁平化一个图像的时候 你可以在想变回3D空间的时候 使用反转
它具有像素焦距 这又是两个不同的数字 不过因为我们的像素是正方形像素 所以它们的数字是一样的
它也有对应着光学中心的x和y坐标
像素值是按照参考帧的分辨率给定的
深度数据可能有很低的分辨率 我们不想把这么低分辨率的像素值 给你们 因此我们提供了一个独立的空间集 它们通常是传感器的完整大小 因此你可以获得很高的精度 以及很高的分辨率 在intrinsicMatrix中
接下来是extrinsicMatrix 这个属性描述的是 现实世界中相机拍摄时的姿态
你会在下面的情景要到这个属性 就是你要用从立体矫正相机得到的图像 进行三角测量的时候 需要将其与另一个图像进行比较 我们的外在功能 一个单一的矩阵 不过有点像是把两个矩阵压到了一起 首先左边的那个是旋转矩阵 它是个3x3的矩阵 用来描述相机如何旋转 根据现实世界的初始状态 不管原来到底是什么样的 另外还有一个1x3的矩阵 它用来描述相机的翻转 或者说相对于现实世界初始状态的距离
需要注意的是 长焦镜头就是现实世界的初始状态 当你使用双摄像头时候很容易就能实现 如果你只想要一个长焦图像 那么你会得到一个单位矩阵 如果你要使用广角和长焦的话 广角就不会是单位矩阵 因为它描述了 其与长焦镜头的姿态和距离 但是通过使用外在功能 你就可以 计算广角和长焦之间的基线
还有其他一些属性是用来处理 我们前面介绍过的 镜头的几何失真的 它们适用于你需要 处理一个图像或是 将深度图直线化的情景
有两个你需要注意的属性 第一个是 lensDistortionCenter 它描述了传感器上 与镜头失真中心重合的点 这通常与镜头的光学中心并不相同 如果你把所有的失真 镜头上的径向失真 看成是树的年轮的话 那么它就是年轮的中心 除了这个失真中心 我们还有一个叫 lensDistortionLookupTable的属性 你可以把它想成是多个浮点 这些浮点会将lensDistortionCenter 连接到最长的半径 如果你从这些浮点上画一些小的圆圈 你就可以得到一些 像是年轮的图案 它会给你展现镜头的径向失真 lensDistortionLookupTable 是一个包含在数据中的C浮点数组
如果沿着这些虚线的每个点都是0的话 你就会得到世界上独一无二的 完美的镜头 它根本没有径向失真 如果这里是一个正值 就表明半径有延长的地方 如果是负值 就表明半径有收缩的地方 但是如果总体来看整个表格 你就可以发现镜头的颠簸情况
要将失真修正应用到一个图像中 首先你要建立一个空的目标缓冲区 然后对它进行逐行遍历 对于每个点 你都要用 lensDistortionLookupTable 在在失真图像中查找对应的值 将该值写入到输出缓冲区中 的正确位置上 这部分代码很难写 我们也知道 所以我们提供一个参考实现方法 你们可以在 AVCameraCalibrationData.h中找到 我们把代码放到了一个头文件中 它被全部注释掉了 它是一个很大的objective C函数 请你们去看一下 它描述了如何纠正一个图像 或是如何反扭曲一个图像 取决于你传给它的表格是什么
如你所想 此表格的逆实现 描述的就是如何从扭曲的图像变回 非扭曲的
用一个演示来给你们解释会容易得多 让我们做个演示吧
这是我们今天的第四个 也是最后一个示例应用 它叫作Straighten Up 我打赌你们能猜出来 它是干什么用的
这个应用使用了 AVCameraCalibrationData 特别是镜头失真特征描述 来让图像直线化
我今天早上在外面的时候 拍了一些双镜头照片 你们应该可以看出来这些是双照片 而且我是放大了两倍 因为它们周围有黑边 这张当然是用长焦镜头拍的
而这张是失真的照片
现在当我点击 Undistort按钮的时候 你就会发现一些细微的变化
你绝对是可以发现的 不过这些变化真的很小 通常长焦镜头具有更小的曲率 这样它们就在边缘上 具有比广角镜头更小的径向失真 我会放大一点 这样你们就能看出差别了 这是直线的 直线是直的 而这条是扭曲的 现在如果我看下广角的照片
虽然我们没有角落的信息
但是你们还是可以看到 在我们已有的图像数据中 失真还是要更明显些
按distorted 按undistorted 按distorted 按undistorted 你绝对可以发现 在边缘附近 图像被向内拉伸得更多
按undistorted 按distorted 按undistorted
好了 回到幻灯片中
(总结) 我们该总结一下了
iPhone 7 Plus的双摄像头 不是渡越时间的相机系统 它是一个? 视差 视差系统 如果你今天只记住一点 那么我希望你们能记住 视差和深度有什么不同之处
另外 我们平台上对于深度的规范表示 应该是AVDepthData
我们还介绍了内在功能 外在功能 镜头失真 这些都是 AVCameraCalibrationData的属性
我们介绍了 AVCaptureDepthDataOutput 它所提供的流式深度 是你可以自己选择是否进行过滤的
我们还介绍了如何使用 AVCapturePhotoOutput来拍照 并且让这些照片带有深度信息
最后我们花了点时间介绍双摄像头 双照片送达 双照片会给单张照片生成广角 和长焦照片 这样就能实现有趣的计算机视觉任务了 我希望你们可以去试试
我们有三个示例代码 现在就已经可供查阅了 它们都跟本次演讲相关联了 分别是AVCam PhotoFilter和Wiggle Me
有关它们的更多信息 请参见这个网址的链接
请再稍等一会儿 紧接着这个演讲的 是一个非正式的开发者聚会 与会者都是对摄影感兴趣的开发者 你们都是其中一员啊
那你们可以来跟Apple 多媒体技术组的成员聊聊天
你可以问些问题 或者我们就是闲聊 社交一下 明天11点有一个本演讲的姊妹演讲 你可以学到如何读取并处理 图像文件中的深度数据 今天我们只是浅显地 介绍了一下 你可以利用深度照片实现什么 明天会有很多的演示 我真的希望你们 明天可以抽出时间来听一下 如果你们能来的话 我深感荣幸
最后主讲一个关于 如何处理HEIF的演讲 这个演讲是在周五上午举行 我希望你们也能来
在那个演讲中 我会深入介绍一下 AVCapturePhoto接口
谢谢 希望你们享受大会剩余的演讲
-
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。