You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何判断ARSession中的ARFaceAnchor未更新及人脸移出视野?

解决AR人脸追踪中人脸移出视野无法感知的问题

这个问题其实是ARFaceTrackingConfiguration的默认行为导致的——人脸移出摄像头视野后,ARSession并不会自动移除对应的ARFaceAnchor,所以session(_:didRemove anchors:)确实不会被触发。而且一旦人脸完全脱离追踪范围,session(_:didUpdate anchors:)也会停止调用,因为没有锚点状态变化了。不过我们可以通过以下几种方式来解决:

核心思路:利用ARFaceAnchor.isTracked属性+帧级检查

ARFaceAnchor有个关键的isTracked属性:当人脸在视野内且被稳定追踪时,它的值是true;当人脸移出视野或者追踪丢失时,会变为false。我们可以结合这个属性,加上对每帧的锚点检查,来判断人脸是否已经离开。

步骤1:保存追踪人脸的标识

首先定义变量来记录当前追踪的人脸锚点UUID和追踪状态:

// 记录当前追踪的人脸锚点UUID
var trackedFaceUUID: UUID?
// 标记上一帧人脸是否处于被追踪状态
var wasFaceTracked = false
// 保存你的人脸锚点副本
var savedFaceAnchor: ARFaceAnchor?

步骤2:在锚点更新时同步状态

在session(_:didUpdate anchors:)里更新锚点副本,并记录追踪状态:

func session(_ session: ARSession, didUpdate anchors: [ARAnchor]) {
    for anchor in anchors {
        guard let faceAnchor = anchor as? ARFaceAnchor else { continue }
        
        // 更新当前追踪的人脸UUID
        trackedFaceUUID = faceAnchor.uuid
        // 保存锚点副本
        savedFaceAnchor = faceAnchor.copy() as? ARFaceAnchor
        
        if faceAnchor.isTracked {
            wasFaceTracked = true
            // 这里可以处理人脸正在被追踪的逻辑
        } else {
            // 首次检测到追踪丢失,触发人脸移出逻辑
            handleFaceOutOfFrame()
            wasFaceTracked = false
        }
    }
}

步骤3:帧级检查确保不遗漏

如果人脸完全移出后,session(_:didUpdate anchors:)可能不再被调用,所以需要在每帧更新时主动检查锚点状态。你可以选择两种回调方式:

方式A:利用ARSession的帧更新回调

实现session(_:didUpdate frame:)方法,在每帧里检查当前会话中的人脸锚点:

func session(_ session: ARSession, didUpdate frame: ARFrame) {
    guard let trackedUUID = trackedFaceUUID else { return }
    
    // 在当前帧的锚点中查找我们追踪的人脸
    let currentFaceAnchor = frame.anchors.first {
        $0.uuid == trackedUUID && $0 is ARFaceAnchor
    } as? ARFaceAnchor
    
    if let faceAnchor = currentFaceAnchor {
        // 人脸锚点存在但已停止追踪
        if !faceAnchor.isTracked && wasFaceTracked {
            handleFaceOutOfFrame()
            wasFaceTracked = false
        }
    } else {
        // 人脸锚点已经不存在,确认人脸完全丢失
        if wasFaceTracked {
            handleFaceOutOfFrame()
            wasFaceTracked = false
            trackedFaceUUID = nil
        }
    }
}

方式B:如果用SceneKit,利用渲染器的帧更新回调

如果你用SceneKit渲染AR内容,可以实现renderer(_:updateAtTime:):

func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) {
    guard let session = renderer.session,
          let trackedUUID = trackedFaceUUID else { return }
    
    let currentFaceAnchor = session.currentFrame?.anchors.first {
        $0.uuid == trackedUUID && $0 is ARFaceAnchor
    } as? ARFaceAnchor
    
    // 逻辑和上面的帧更新回调一致
    if let faceAnchor = currentFaceAnchor {
        if !faceAnchor.isTracked && wasFaceTracked {
            handleFaceOutOfFrame()
            wasFaceTracked = false
        }
    } else {
        if wasFaceTracked {
            handleFaceOutOfFrame()
            wasFaceTracked = false
            trackedFaceUUID = nil
        }
    }
}

步骤4:实现人脸移出后的处理逻辑

最后写好handleFaceOutOfFrame()函数,处理人脸移出后的业务:

func handleFaceOutOfFrame() {
    // 这里写人脸移出视野后的逻辑,比如重置状态、显示提示等
    print("人脸已移出摄像头视野")
    savedFaceAnchor = nil
}

补充说明

为什么session(_:didRemove anchors:)不触发?因为ARFaceTrackingConfiguration默认不会自动移除人脸锚点——只有当你设置maximumNumberOfTrackedFaces为大于1的值,且有新的人脸进入视野替换旧的追踪对象,或者ARSession被重置时,才会调用这个方法。所以完全不能依赖它来检测单个人脸的移出。

内容的提问来源于stack exchange,提问作者user14492

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 09:35:04