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

如何借助ARFaceAnchor与RealityKit检测人脸是否完全可见且居中?

解决方案:ARFaceAnchor人脸边界与屏幕坐标系转换

一、获取人脸在相机空间的边界范围

ARFaceAnchor没有直接提供minX/maxX这类属性,可通过两种方式计算面部边界:

方式1:基于面部几何顶点计算精确包围盒

利用ARFaceAnchor的geometry属性(对应ARFaceGeometry)遍历所有面部顶点,计算相机空间下的边界极值:

import ARKit

func getFaceBoundingBox(from anchor: ARFaceAnchor) -> CGRect {
    let faceGeometry = anchor.geometry
    var minX: Float = .greatestFiniteMagnitude
    var maxX: Float = -.greatestFiniteMagnitude
    var minY: Float = .greatestFiniteMagnitude
    var maxY: Float = -.greatestFiniteMagnitude
    
    // 将顶点转换到相机空间并计算极值
    for vertex in faceGeometry.vertices {
        let vertexInCameraSpace = anchor.transform * SIMD4<Float>(vertex.x, vertex.y, vertex.z, 1)
        minX = min(minX, vertexInCameraSpace.x)
        maxX = max(maxX, vertexInCameraSpace.x)
        minY = min(minY, vertexInCameraSpace.y)
        maxY = max(maxY, vertexInCameraSpace.y)
    }
    
    return CGRect(x: CGFloat(minX), y: CGFloat(minY), width: CGFloat(maxX - minX), height: CGFloat(maxY - minY))
}

方式2:基于面部特征点快速估算边界

如果不需要极高精度,可利用ARFaceAnchor提供的特征变换矩阵(如眼、鼻、下巴)快速估算面部范围:

func getFaceApproximateBounds(from anchor: ARFaceAnchor) -> CGRect {
    // 选取关键面部特征点的位置
    let keyPoints = [
        anchor.leftEyeTransform.columns.3,
        anchor.rightEyeTransform.columns.3,
        anchor.noseTransform.columns.3,
        anchor.chinTransform.columns.3
    ]
    
    var minX: Float = .greatestFiniteMagnitude
    var maxX: Float = -.greatestFiniteMagnitude
    var minY: Float = .greatestFiniteMagnitude
    var maxY: Float = -.greatestFiniteMagnitude
    
    for point in keyPoints {
        minX = min(minX, point.x)
        maxX = max(maxX, point.x)
        minY = min(minY, point.y)
        maxY = max(maxY, point.y)
    }
    
    // 扩展边界以覆盖完整面部
    let expandRatio: Float = 1.2
    let width = (maxX - minX) * expandRatio
    let height = (maxY - minY) * expandRatio
    let centerX = (minX + maxX) / 2
    let centerY = (minY + maxY) / 2
    
    return CGRect(x: CGFloat(centerX - width/2), y: CGFloat(centerY - height/2), width: CGFloat(width), height: CGFloat(height))
}

二、将相机空间坐标转换为屏幕坐标系

通过ARSession的相机对象,调用projectPoint(_:)方法完成坐标转换,同时适配UI坐标系的Y轴方向:

func convertCameraSpaceBoundsToScreen(_ cameraSpaceBounds: CGRect, session: ARSession, screenSize: CGSize) -> CGRect {
    guard let camera = session.currentFrame?.camera else { return .zero }
    
    // 转换包围盒的左上、右下顶点到屏幕空间
    let topLeft = camera.projectPoint(SIMD3<Float>(Float(cameraSpaceBounds.minX), Float(cameraSpaceBounds.maxY), 0))
    let bottomRight = camera.projectPoint(SIMD3<Float>(Float(cameraSpaceBounds.maxX), Float(cameraSpaceBounds.minY), 0))
    
    // 适配UIKit的Y轴原点(若用SwiftUI可省略Y轴翻转)
    let screenMinX = CGFloat(topLeft.x)
    let screenMaxX = CGFloat(bottomRight.x)
    let screenMinY = screenSize.height - CGFloat(bottomRight.y)
    let screenMaxY = screenSize.height - CGFloat(topLeft.y)
    
    return CGRect(x: screenMinX, y: screenMinY, width: screenMaxX - screenMinX, height: screenMaxY - screenMinY)
}

三、判断人脸是否贴近中央椭圆边界

假设你已获取屏幕中央椭圆的CGRect(如centralEllipseFrame),可通过阈值判断人脸与椭圆边界的距离:

func isFaceNearEllipseBounds(faceScreenBounds: CGRect, centralEllipseFrame: CGRect) -> Bool {
    // 设置贴近阈值(单位:pt)
    let threshold: CGFloat = 10
    
    // 检查人脸边界是否在椭圆阈值范围内
    let isNearLeft = faceScreenBounds.maxX >= centralEllipseFrame.minX - threshold
    let isNearRight = faceScreenBounds.minX <= centralEllipseFrame.maxX + threshold
    let isNearTop = faceScreenBounds.minY >= centralEllipseFrame.minY - threshold
    let isNearBottom = faceScreenBounds.maxY <= centralEllipseFrame.maxY + threshold
    
    return isNearLeft && isNearRight && isNearTop && isNearBottom
}

注意事项

  • 建议在ARSessionDelegate的session(_:didUpdate:)方法中实时更新人脸边界并执行判断逻辑。
  • 若使用SwiftUI,屏幕坐标系Y轴与ARKit一致(原点左上角),无需额外翻转;UIKit则需保留代码中的Y轴转换。
  • 面部深度(Z轴坐标)会影响投影精度,若需要更精准判断,可统一使用面部中心的Z值进行投影计算。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 10:07:47