如何实现类似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
相关产品推荐
相关产品推荐

