ARKit 同时使用前置和后置摄像头

1,208 阅读5分钟

Combining User Face-Tracking and World Tracking

在显示后置摄像头增强现实体验的应用程序中跟踪用户的脸。

概述

当在世界跟踪会话中跟踪用户的面孔时,ARKit将来自前置和后置摄像头馈送的信息集成到AR体验中。除了使用后置摄像头跟踪物理环境外,ARKit还使用前置摄像头提供锚,提供用户面部的位置和表情。

为了演示在跟踪世界时应用用户的脸,此示例应用程序允许用户放置反映用户面部表情的机器人头部。

配置并开始会话

此应用程序在iOS 13和iPad OS 13或更高版本上的世界跟踪会话中,在配备前原深感摄像头的设备上跟踪用户的脸,该摄像头将“true”返回'supportsUserFaceTracking'。为了防止应用程序运行不受支持的配置,请检查iOS设备是否支持同时进行世界和用户面部跟踪。

image.png

如果运行该应用程序的设备不支持在世界跟踪会话中的用户面部跟踪,示例项目将停止。在您的应用程序中,在这种情况下,考虑优雅地降低AR体验,例如向用户显示错误信息,并在没有它的情况下继续体验。

当应用程序加载视图控制器时,示例应用程序在世界跟踪配置上将userFaceTrackingEnabled属性设置为“true”。

image.png

然后,当视图控制器即将出现在屏幕上时,示例应用程序通过运行配置来启动会话。

image.png

在物理环境中预览虚拟内容

该应用程序检查机器人头部预览是否存在,如果没有,则创建一个。ARKit调用session(_:didUpdate:)每个帧的实现,使其成为定期检查的好位置。

image.png

检测用户表达式的变化

当用户更改其相对于世界的表达式、位置或方向时,ARKit为应用程序提供了一个更新的锚点。如果有活跃的机器人头部预览,该应用程序会将这些更改应用于头部。

image.png

检查表达信息

在机器人头部的“更新(带有faceAnchor:)”功能中,应用程序通过解释锚的混合形状来读取用户的当前表达式。

image.png

混合形状是在“[0.1]”范围内正常化的“浮动”值,其中“0”代表面部特征的休息位置,“1”代表相反的位置——最明显的特征。要开始处理值,应用程序通过访问锚的blendShapes数组将其存储在本地。

guard let eyeBlinkLeft = blendShapes[.eyeBlinkLeft] as? Float,    let eyeBlinkRight = blendShapes[.eyeBlinkRight] as? Float,    let eyeBrowLeft = blendShapes[.browOuterUpLeft] as? Float,    let eyeBrowRight = blendShapes[.browOuterUpRight] as? Float,    let jawOpen = blendShapes[.jawOpen] as? Float,    let upperLip = blendShapes[.mouthUpperUpLeft] as? Float,    let tongueOut = blendShapes[.tongueOut] as? Float    else { return }

对用户的表达方式做出反应

根据应用程序的要求,混合形状值可以以独特的方式应用。示例应用程序使用混合形状使机器人头部看起来模仿用户的表情,例如应用眉毛和嘴唇值来抵消机器人的眉毛和嘴唇位置。

eyebrowLeftEntity.position.y = originalEyebrowY + 0.03 * eyeBrowLeft
eyebrowRightEntity.position.y = originalEyebrowY + 0.03 * eyeBrowRight
tongueEntity.position.z = 0.1 * tongueOut
jawEntity.position.y = originalJawY - jawHeight * jawOpen
upperLipEntity.position.y = originalUpperLipY + 0.05 * upperLip

当示例应用程序应用相应的混合形状值作为比例因子时,机器人眼睛的实体会打开或关闭。

image.png

定位机器人头

除了使用前置摄像头捕捉用户的表情外,ARKit还记录用户面部相对于世界的位置。根据设计,用户的面部锚始终位于后置摄像头后面。为了实现用机器人头模仿用户的目标,示例应用程序应用面部锚的位置,使机器人头部始终可见。首先,它设置机器人头部的初始位置与相机的位置相等。

image.png

然后,该应用程序以与相机与用户面部的距离相同的数量抵消其z位置。

let cameraTransform = parent.transformMatrix(relativeTo: nil)
let faceTransformFromCamera = simd_mul(simd_inverse(cameraTransform), faceAnchor.transform)
self.position.z = -faceTransformFromCamera.columns.3.z

定位机器人头

示例应用程序还使用锚的方向不断将机器人头部前部指向相机。它从访问锚的方向开始。 然后,它将“pi”添加到“y”-Euler角度,以打开y轴。

let rotationEulers = faceTransformFromCamera.eulerAngles
let mirroredRotation = Transform(pitch: rotationEulers.x, yaw: -rotationEulers.y + .pi, roll: rotationEulers.z)


为了影响更改,该应用程序将更新后的欧拉角度应用于机器人头部的方向。

self.orientation = mirroredRotation.rotation

通过放置头部捕捉表情

为了演示会话期间跟踪的各种表达式,当用户轻点屏幕时,示例应用程序将机器人头放置在物理环境中。当应用程序最初预览表达式时,它会将机器人头部定位在相机的固定偏移量处。当用户轻点屏幕时,该应用程序通过将其位置更新到当前世界位置来识别机器人头部。

@objcfunc handleTap(recognizer: UITapGestureRecognizer) {   
guard let robotHeadPreview = headPreview, robotHeadPreview.isEnabled, robotHeadPreview.appearance == .tracked else {        return    }    
let headWorldTransform = robotHeadPreview.transformMatrix(relativeTo: nil)    robotHeadPreview.anchor?.reanchor(.world(transform: headWorldTransform))    robotHeadPreview.appearance = .anchored    // ...


将“headPreview”设置为“nil”可以防止应用程序更新“session(didUpdate anchors:)”中的面部表情,这将冻结放置在放置的机器人头上的表情。

self.headPreview = nil

当ARKit再次调用“session(didUpdate frame:)”时,该应用程序会检查是否存在机器人头部预览,如果没有,则创建一个。

func session(_ session: ARSession, didUpdate frame: ARFrame) { 
if headPreview == nil, case .normal = frame.camera.trackingState {        addHeadPreview()    
}    //...

当应用程序将“headPreview”设置为“nil”时,它会创建另一个机器人头部预览,延续了用户放置对象和归档其他面部表情的能力。

亲测iphone x 不支持 ,只能找一个支持的设备测试了。。。。。