515d98a25937f288a0c7bbbe1954d3f3
WWDC 2018:理解 ARKit 的追踪和检测

今年的 Session 610 - Understanding ARKit Tracking and Detection 内容如下:


本session主要讲的是原有的三种追踪和检测方式:朝向追踪,世界追踪,平面检测


还有本次添加的三种新的追踪和检测方式:保存和加载地图,图片追踪,物体检测.

ARKit基础

ARKit运行的主要结构如下:


首先是创建一个ARSession,它综合处理AR中的一切,包括加载配置,运行AR技术,返回结果等.

接着是指定一个ARConfiguration,说明你到底要运行哪种AR技术,是图片追踪,还是平面检测.并通过调用ARSession实例的run(_ configuration)来运行.

然后ARSession会在内部自动开始接收AVCaptureSession传来的图像信息和CMMotionManager传来的传感器数据.

经过ARKit处理后,会得到一秒60帧的ARFrame.它不仅包含了从摄像头得到的图像也就是AR的场景背景图像,还包括了摄像机的运动情况可用于渲染虚拟场景中的摄像机,此外还有外部环境信息,比如已探测到的平面.

朝向追踪

只追踪朝向(3 DoF):可用于模拟头部的旋转

一般用于球形虚拟场景,或者远处物体的渲染.

但是不能用来在不同位置观察对现实世界的增强结果(即不能移动到不同的位置).

幕后的秘密

技术很简单,只用到了旋转信息,因为运动传感器的更新频率很快,所以当相机传感器的图像信息可用时,取最新的运动状态,将两者在ARFrame中返回出去.

需要注意:在这种模式下,相机获取的数据并没有经过任何计算机视觉系统处理,也就是说没有特征点之类的视觉信息,只是单纯的图像+传感器姿态信息.

朝向追踪API

API也很简单,transform中只包含了旋转信息,或者也可以使用欧拉角,作用是一样的.

AROrientationTrackingConfiguration
open class ARCamera : NSObject, NSCopying {
    open var transform: simd_float4x4 { get }
    open var eulerAngles: simd_float3 { get } ...
}

世界追踪

世界追踪是6 DoF追踪,可以在场景中旋转和移动.

幕后的秘密

ARKit使用的是视觉惯性里程计(VIO),它结合了惯性里程计和视觉里程计的优点:
惯性里程计:利用运动传感器高频采样速度快精度高,可准确捕捉快速和剧烈的运动,但长期会有累积误差;
视觉里程计:利用摄像头图像+计算机视觉(CV)处理,无时间累积误差,但处理速度慢,无法在快速和剧烈运动时使用;

视觉惯性里程计(VIO)综合了它们的优点,不仅精度高,无长期累积误差,甚至在短时间无视频画面时仍能保持追踪.

整体过程是:提取场景中的鲁棒性特征(即明显的特征点)-->匹配特征点-->三角定位创建世界地图-->AR初始化-->通过ARAnchor放置增强现实物体-->继续追踪更多特征点-->优化追踪的健壮性(画面上的虚拟物体可能会轻微调整位置)
在三角定位中,必须有真实的移动,纯粹的旋转无法得到三角定位信息.

在最后一步中,完成了视觉惯性SLAM(即时定位与地图构建)操作,提高了对整个场景的认识.

最后一步,完成地图构建后,还会利用已经构建的地图和特征点来优化相机定位的准确度,因此会有轻微的跳动出现.

世界追踪 API

ARWorldTrackingConfiguration
open class ARCamera : NSObject, NSCopying {
   open var transform: simd_float4x4 { get }

   //以下两个提供了追踪质量的反馈
   open var trackingState: ARTrackingState { get }
   open var trackingStateReason: ARTrackingStateReason { get }
   ...
}

世界追踪的质量

对追踪质量产生影响的有以下因素:

不间断的传感器数据:ARKit可以容忍短时间的数据中断,但长时间中断会让session变成受限状态(Limited).
富有纹理的环境:环境需要富有纹理细节,并有充分光照.因为三角定位需要明显的特征点和复杂的纹理细节.环境太暗,或面对一面白色墙壁会让追踪质量变差.
静止的场景:世界追踪需要场景是静止的,如果在移动的电梯中或车辆中使用,运动传感器得出的数据和摄像头画面分析得出的结果会不一致.


ARKit使用了机器学习技术来增强对图像和传感器数据的分析.根据不同条件使用不同的方案来追踪.如下,在摄像头被遮挡时,追踪的"健康度"会下降,画面恢复后,"健康度"上升.

ARKit会把追踪状态规范成四种不同的状态:没启动时是Not Available,启动中是Limited,启动成功Normal,被遮挡是Limited,恢复后还是Normal:

状态改变会在下面的回调方法中通知:

 // Called when tracking state changed
func session(_ session: ARSession, cameraDidChangeTrackingState camera: ARCamera) {
    if case .limited(let reason) = camera.trackingState {
        // Guide user to improve tracking state
        ...
    }
}

平面检测

平面检测用到了前面创建的世界地图来检测存在的水平和竖直平面,需要注意的是可能会有多个平面,而且平面会合并;
ARKit 2引用了一个新特性:竖直平面和水平平面的交界处可以互相截断,更加真实.

幕后的秘密

平面检测的原理就是根据得到的3D特征点,构成平面,并不断更新扩展平面/合并平面;
需要注意的是:平面检测无法立即得到,因此需要开发者引导用户适当移动,检测更多的3D特征点以便构成平面.只在原地旋转同样是不行的.

平面检测API

平面检测用的配置和世界追踪一样,只是多个属性设置.

// Create a world tracking configuration
let configuration = ARWorldTrackingConfiguration()
// Enable plane detection
configuration.planeDetection = [.horizontal, .vertical]
// Run the session
session.run(configuration)

平面检测得到的结果是ARPlaneAnchor,并会在代理中持续得到它的添加/移除/更新信息

open class ARPlaneAnchor : ARAnchor {
  // 位置和方向
  open var transform: simd_float4x4 { get }
  // 中心点位置和边界盒尺寸
  open var center: simd_float3 { get }
  open var extent: simd_float3 { get }
  // 平面几何体形状
  open var geometry: ARPlaneGeometry { get }
    ...
}

边界盒尺寸和几何体形状到底是什么见下图:

得到平面后,你就可以放置虚拟物体或者进行命中测试(hitTest)了.

保存和加载世界地图

这个功能可以完成:

  • 获取高质量的世界地图
  • 共享这个世界地图
  • 重定位到世界地图中

世界地图数据

世界地图中包含的数据有:

  • 内部追踪数据
    • 3D特征点地图
    • 本地外观
  • 锚点名称列表
  • 可序列化

获取一个高质量的世界地图

流程如下图

注意事项:

  • 地图上需要有稠密的特征点
  • 环境必须是静态的,无移动,无变化
  • 有多个视点(即从多个不同位置获取场景)
  • 世界地图构建状态:Not Available,Limited,Extending,Mapped

在地图构建的过程中,开发者需要及时提示用户:

  • 显示地图构建状态
  • 提醒追踪状态受限
  • 引导重定位

共享世界地图

基本过程是这样:

// Retrieve world map from ARSession
session.getCurrentWorldMap { worldMap, error in
    guard let worldMap = worldMap else {
        showAlert(error)
    return
}
    // Serialize
    let data = try NSKeyedArchiver.archivedData(withRootObject: worldMap, requiringSecureCoding: true)
}

如果需要共享给他人----使用MultipeerConnectivity framework
具体用法见示例程序“Creating a Multiuser AR Experience”<见本文末尾>

重定位到世界中

// Receive / Load world map
let worldMap : ARWorldMap = ...

// Create a session configuration
let configuration = ARWorldTrackingConfiguration()
configuration.initialWorldMap = worldMap

// Run the session
session.run(configuration)

在重定位完成前:

  • 追踪状态是Limited
  • 原因为Relocalizing
  • 世界坐标原点将会是你session启动后第一个摄像机位置

在重定位完成后:

  • 追踪状态为Normal
  • 世界坐标原点是世界地图中的初始化原点
top Created with Sketch.