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

如何实现类似FaceID的iPhone用户注意力检测?求Vision Framework相关方案

实现iPhone注视检测(类似FaceID功能)

核心实现方案(基于Vision Framework)

Vision Framework本身没有直接提供注视检测的API,但可以通过人脸关键点检测,分析瞳孔与眼睛轮廓的相对位置来实现类似功能。以下是完整的Swift代码示例:

import UIKit
import AVFoundation
import Vision

class GazeDetectionVC: UIViewController, AVCaptureVideoDataOutputSampleBufferDelegate {
    private var captureSession: AVCaptureSession!
    private let detectionQueue = DispatchQueue(label: "com.yourapp.gazedetection")
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupCameraSession()
    }
    
    private func setupCameraSession() {
        captureSession = AVCaptureSession()
        captureSession.sessionPreset = .medium
        
        // 获取前置摄像头
        guard let frontCam = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .front) else {
            fatalError("前置摄像头不可用")
        }
        
        // 创建摄像头输入
        guard let camInput = try? AVCaptureDeviceInput(device: frontCam) else {
            fatalError("无法初始化摄像头输入")
        }
        
        if captureSession.canAddInput(camInput) {
            captureSession.addInput(camInput)
        }
        
        // 设置视频输出与代理
        let videoOutput = AVCaptureVideoDataOutput()
        videoOutput.setSampleBufferDelegate(self, queue: detectionQueue)
        if captureSession.canAddOutput(videoOutput) {
            captureSession.addOutput(videoOutput)
        }
        
        captureSession.startRunning()
    }
    
    // 处理摄像头帧数据
    func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
        guard let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return }
        
        // 创建人脸关键点检测请求
        let landmarkRequest = VNDetectFaceLandmarksRequest(completionHandler: handleLandmarkResults)
        let imageHandler = VNImageRequestHandler(cvPixelBuffer: pixelBuffer, orientation: .leftMirrored)
        
        do {
            try imageHandler.perform([landmarkRequest])
        } catch {
            print("检测失败: \(error.localizedDescription)")
        }
    }
    
    // 处理人脸关键点结果
    private func handleLandmarkResults(request: VNRequest, error: Error?) {
        guard let faceObservations = request.results as? [VNFaceObservation], let face = faceObservations.first else {
            print("未检测到人脸")
            return
        }
        
        guard let faceLandmarks = face.landmarks, let leftEye = faceLandmarks.leftEye, let rightEye = faceLandmarks.rightEye else {
            print("未检测到眼睛关键点")
            return
        }
        
        // 计算双眼中心点
        let leftEyeCenter = calculateEyeCenter(eye: leftEye)
        let rightEyeCenter = calculateEyeCenter(eye: rightEye)
        
        // 判断是否注视屏幕
        let isGazingAtScreen = checkGazeValidity(leftEyeCenter: leftEyeCenter, leftEyeBounds: leftEye.boundingBox,
                                                 rightEyeCenter: rightEyeCenter, rightEyeBounds: rightEye.boundingBox)
        
        DispatchQueue.main.async {
            // 这里可以更新UI或执行业务逻辑
            print(isGazingAtScreen ? "正在注视屏幕" : "未注视屏幕")
        }
    }
    
    // 计算眼睛中心点(基于关键点平均)
    private func calculateEyeCenter(eye: VNFaceLandmarkRegion2D) -> CGPoint {
        let points = eye.normalizedPoints
        let avgX = points.reduce(0) { $0 + $1.x } / CGFloat(points.count)
        let avgY = points.reduce(0) { $0 + $1.y } / CGFloat(points.count)
        return CGPoint(x: avgX, y: avgY)
    }
    
    // 判断注视有效性(通过瞳孔与眼睛边界的相对位置)
    private func checkGazeValidity(leftEyeCenter: CGPoint, leftEyeBounds: CGRect,
                                   rightEyeCenter: CGPoint, rightEyeBounds: CGRect) -> Bool {
        // 阈值可根据实际测试调整,控制检测灵敏度
        let horizontalThreshold: CGFloat = 0.25
        
        // 左眼水平范围判断
        let leftEyeCenterX = leftEyeBounds.midX
        let leftValidRange = (leftEyeCenterX - leftEyeBounds.width * horizontalThreshold)...(leftEyeCenterX + leftEyeBounds.width * horizontalThreshold)
        
        // 右眼水平范围判断
        let rightEyeCenterX = rightEyeBounds.midX
        let rightValidRange = (rightEyeCenterX - rightEyeBounds.width * horizontalThreshold)...(rightEyeCenterX + rightEyeBounds.width * horizontalThreshold)
        
        return leftValidRange.contains(leftEyeCenter.x) && rightValidRange.contains(rightEyeCenter.x)
    }
}

关键注意事项

  • 权限配置:必须在Info.plist中添加NSCameraUsageDescription字段,说明相机使用用途,否则无法获取摄像头权限。
  • 设备兼容性:搭载TrueDepth摄像头的设备(iPhone X及以后机型)能提供更精准的眼睛关键点数据;普通前置摄像头的检测精度有限。
  • 阈值调整:checkGazeValidity中的horizontalThreshold需要根据实际测试调整,适配不同用户的面部特征。

官方文档参考

苹果官方文档中可重点关注以下内容:

  • VNDetectFaceLandmarksRequest类:用于发起人脸关键点检测请求
  • VNFaceObservation的landmarks属性:包含人脸各部位(眼睛、眉毛、嘴巴等)的关键点集合
  • VNFaceLandmarkRegion2D类:提供关键点的归一化坐标与边界信息

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 00:52:30