ARKit系列文章目录 2018年的 Session 610 - Understanding ARKit Tracking and Detection 内容如下(原发表于《WWDC18 内参》): 主要内容速览:
- ARKit基础
- 朝向追踪
- 世界追踪
- 平面检测
- 保存和加载世界地图
- 图片追踪
- 物体检测
本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
- 世界坐标原点是世界地图中的初始化原点
- 只允许环境出现极少量变化(变化太大就无法识别了)
也就是说,当你启动AR后,如果没有对着指定目标,原点就是AR启动时的手机位置,指向目标完成地图重定位后,原点会发生改变,需要特别注意.
图片追踪
图片追踪可识别并追踪场景中出现的图片,可同时追踪多个图片
幕后的秘密
先是本地化图片(Localize the image)
参考图片和场景中当前画面会被转为灰度图像,然后提取双方的特征点信息,然后对特征进行匹配,得出场景中的图片位置和朝向;
接着是稠密追踪(Dense tracking)
从当前画面中截取出重建过的图片(下图右上角),通过与参考图片(下图左上)对比,可以得到一个错误画面(下图中下方),优化这个错误图像,让错误值最小化,就能提高追踪精度.
这样,在场景中的图片被部分遮挡时,也能持续追踪.如下图片被手指和左侧边缘遮挡,左侧是无效部分不会显示在错误画面中,只需要将手指遮挡引起的不匹配优化到最小,就能得到最精确结果.
图片追踪API
首先创建参考图像,然后创建配置,可选世界追踪或图片追踪,最后从ARSession中得到ARFrame,再得到ARImageAnchor.
将图片添加为素材(Assets)
创建参考图片最简单的方式就是将图片拖拽到Xcode中添加为素材.
- 创建AR Resource Group
- 拖拽需要检测的图片
- 设置图片的物理尺寸(单位:米)
设置图片的物理尺寸
图片的物理尺寸是必须设置项,主要作用是和世界追踪得到的数据保持一致.
适合追踪的图片
适合追踪的图片必须有以下特点:
- 丰富的纹理
- 高对比度
- 良好的色彩直方图分布
- 无重复结构(如左半边和右半边完全一样,或两个相同物体)
Xcode中的参考图片质量
所有这些图片质量信息都可以从Xcode中获得.同时,如果两幅图片十分相似也会给出提示.
Xcode现在可以创建多个AR资源组了.这样博物馆之类的AR应用可以在不同房间使用不同图片组.
- 可以检测更多图片
- 每组推荐,最多25张图片
- 可以用代码切换分组
图片追踪配置项
ARImageTrackingConfiguration
和ARWorldTrackingConfiguration
这两个配置项在图片追踪上有什么不同呢?
也就是说,图片追踪配置项只有在对准图片时才有用,只给出图片的相对位置;
而世界追踪会建立世界坐标系,所以可以扩展到图片以外的3D世界中.
比如下图中识别到图片添加气球,就算摄像头离开图片,气球也可以继续在世界坐标中正常运动.
同时,因为ARImageTrackingConfiguration
没有使用到运动传感器,所以这个配置项可以在车辆和电梯上使用.
代码使用:
// Load Images from Assets
let imageSet = ARReferenceImage.referenceImages(inGroupNamed: "Room1", bundle: Bundle.main)
guard let imageSet = imageSet else {
print("Error loading images")
return
}
// Create a session configuration
let configuration = ARImageTrackingConfiguration()
configuration.trackingImages = imageSet
// Run the session
let session = ARSession() session.run(configuration)
获取结果
追踪结果在代理方法中获取
func session(_ session: ARSession, didUpdate anchors: [ARAnchor]) {
for anchor in anchors {
if let imageAnchor = anchor as? ARImageAnchor {...}
}
}
open class ARImageAnchor : ARAnchor, ARTrackable {
open var transform: simd_float4x4 { get }
open var referenceImage: ARReferenceImage { get }
public var isTracked: Bool { get }
}
可用于共享的绝对坐标空间
借助图片追踪功能,我们可以根据图片位置来建立一个多人共享的坐标系.甚至可以在现实世界中,借助某个图片,实现AR导航功能.
物体检测
图片检测和图片追踪,只能用于平面物体,而物体检测可用于3D检测. 比如识别一个小玩具或Nefertiti奈费尔提蒂(公元前14世纪埃及王后)的雕像.
不过在检测之前,需要先对物体进行扫瞄.
如何获得一个物体?
扫瞄物体类似于建立世界地图.可使用“Scanning and Detecting 3D Objects”示例程序<下载链接见文章末尾>.物体扫瞄的质量会影响物体检测的质量.
打开“Scanning and Detecting 3D Objects”示例程序,点击开始扫瞄物体,会自动生成并不断调整边界盒子.你也可以手动拖动来调整边界盒子的大小,或者用双指旋转盒子以避免个别部位突出边界.
接着是对各个面的扫瞄,希望从哪个面进行识别,就对哪个面进行扫瞄,可以离近点以获得更好的扫瞄效果.
最后可以拖动调整物体坐标原点.
为了检测扫瞄效果,可以将app切换到"检测"模式,试试能不能检测到刚才扫瞄的物体.
试着将摄像头对准别处,再移动回来,看不能顺利检测到物体;
试着将物体移动到其他地方,比如灯光不同的地方,测试能否重新检测到物体;
如果不能顺利识别,应调整重新进行扫瞄.
物体扫瞄
如果对效果满意,就可以分享到Xcode中,以供检测识别.
适合追踪的物体
适合用于追踪的物体应有以下特点:
- 刚性物体
- 纹理细节丰富
- 无表面反射
- 无透明效果
物体追踪API
API类似于图片追踪
// Load Objects from Assets
let objects = ARReferenceObjects.referenceObjects(inGroupNamed: "Object", bundle: Bundle.main)
guard let objects = objects else {
print("Error loading objects")
return
}
// Create a session configuration
let configuration = ARWorldTrackingConfiguration()
configuration.detectionObjects = objects
// Run the session
let session = ARSession() session.run(configuration)
获取结果
检测结果也是在代理方法中获取
func session(_ session: ARSession, didUpdate anchors: [ARAnchor]) {
for anchor in anchors {
if let objectAnchor = anchor as? ARObjectAnchor {
let objectName = objectAnchor.referenceObject.name ?? ""
print("Object found: \(objectName)")
}
}
}
物体追踪vs.世界地图重定位
你可能会觉得物体追踪
和世界地图重定位
有点类似,但其实它们还是有一些不同的.
在物体追踪
中最重要的是给出识别到的物体,在世界坐标系中的位置;而在世界地图重定位
中则是给出摄像机在世界地图中的位置;
另外,物体追踪
中可以识别多个物体.最适用于识别追踪放在桌面上或家具上的物体,因为下面的物体可提供有效支持有助识别.
相关资源:
- ARReferenceObject
- ARWorldMap
- Building Your First AR Experience
- Creating a Multiuser AR Experience
- Human Interface Guidelines - Augmented Reality
- Managing Session Lifecycle and Tracking Quality
- Scanning and Detecting 3D Objects
- SwiftShot: Creating a Game for Augmented Reality
- Presentation Slides (PDF)
WWDC2018相关视频:
- Inside SwiftShot: Creating an AR Game
- Integrating Apps and Content with AR Quick Look
- What’s New in ARKit 2
WWDC2017相关视频: