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

Swift 4中基于摄像头的实时人脸追踪问题咨询

关于Swift人脸追踪的两个问题解答

嘿,我来帮你把这些问题理清楚~

一、旧代码无效的原因:代理方法的变更

没错,你猜的完全正确——Swift 4之后AVCaptureOutput的代理方法确实有了关键性修改,这就是你旧代码运行无效果的核心原因!

早期的方法签名是这样的:

func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, from connection: AVCaptureConnection!)

而Swift 4及以后,苹果调整了参数的可选性和命名,正确的代理方法签名应该是:

func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
    // 这里处理摄像头输出的帧数据
}

关键变化点:

  • 移除了所有参数后的!(隐式可选类型),改为非可选类型
  • 参数名从captureOutput简化为output,didOutputSampleBuffer简化为didOutput

如果你的代码还在使用旧的方法签名,系统会认为这是一个自定义方法,不会触发AVCapture的代理回调,自然就看不到任何效果了。

二、用CIFaceFeature监测人脸关键点的实现步骤

要实现人脸关键点监测,你可以在上面的新代理方法里,结合CIDetector和CIFaceFeature来处理每帧画面,具体步骤如下:

1. 提前创建人脸检测器

建议在类初始化时创建,避免重复初始化消耗性能:

private lazy var faceDetector: CIDetector = {
    // 配置检测器选项:高精度+开启追踪
    let options = [
        CIDetectorAccuracy: CIDetectorAccuracyHigh,
        CIDetectorTracking: true,
        CIDetectorLandmarks: true // 必须开启这个才能检测关键点
    ] as [String: Any]
    return CIDetector(ofType: CIDetectorTypeFace, context: nil, options: options)!
}()

2. 在代理方法中处理帧数据并检测人脸

func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
    // 1. 将SampleBuffer转换为CIImage
    guard let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return }
    let ciImage = CIImage(cvImageBuffer: imageBuffer)
    
    // 2. 检测人脸特征
    guard let faceFeatures = faceDetector.features(in: ciImage) as? [CIFaceFeature] else { return }
    
    // 3. 遍历人脸,提取关键点
    for face in faceFeatures {
        // 基础关键点:左眼、右眼、鼻子、嘴巴
        if face.hasLeftEyePosition {
            let leftEyePoint = convertCItoUIKitPoint(face.leftEyePosition, imageSize: ciImage.extent.size)
            print("左眼坐标:\(leftEyePoint)")
        }
        if face.hasRightEyePosition {
            let rightEyePoint = convertCItoUIKitPoint(face.rightEyePosition, imageSize: ciImage.extent.size)
            print("右眼坐标:\(rightEyePoint)")
        }
        
        // 更精细的关键点:比如眼睛轮廓、嘴巴轮廓(需要开启CIDetectorLandmarks)
        if let leftEyeLandmarks = face.leftEyeLandmarks {
            for point in leftEyeLandmarks.pointsInImage(imageSize: ciImage.extent.size) {
                let convertedPoint = convertCItoUIKitPoint(point, imageSize: ciImage.extent.size)
                print("左眼轮廓点:\(convertedPoint)")
            }
        }
    }
}

// 辅助方法:转换CoreImage坐标系到UIKit坐标系(CoreImage原点在左下角,UIKit在左上角)
private func convertCItoUIKitPoint(_ point: CGPoint, imageSize: CGSize) -> CGPoint {
    return CGPoint(x: point.x, y: imageSize.height - point.y)
}

注意事项

  • 必须在检测器配置中设置CIDetectorLandmarks: true,否则无法获取精细的轮廓关键点
  • 坐标转换很重要,否则你拿到的点会和屏幕显示的位置颠倒
  • 如果需要实时绘制关键点,建议把绘制逻辑放到主线程执行(因为代理方法在子线程)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:14:00