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

Google Mobile Vision无法检测CIImage中人脸的问题排查

解决Google Mobile Vision API在相机流中无法检测人脸的问题

问题背景

你提到在相机流中使用Google Mobile Vision API检测人脸/微笑时完全失效,但Apple Vision API能正常工作,即使调整图像方向后仍未解决。下面针对你的两个核心问题和额外排查点给出具体解决方案:


问题A:正确使用GMVDetectorImageOrientation设置图像方向

Google人脸检测器依赖正确的图像方向参数才能准确识别,你需要把设备方向转换成对应的GMV枚举值,并且要和相机捕获的帧方向匹配。

1. 设备方向转GMV方向的工具函数

先写一个转换函数,把UIDeviceOrientation映射到Google检测器需要的方向值:

func gmvOrientation(from deviceOrientation: UIDeviceOrientation) -> Int {
    switch deviceOrientation {
    case .portrait:
        return GMVDetectorImageOrientation.topLeft.rawValue
    case .portraitUpsideDown:
        return GMVDetectorImageOrientation.bottomRight.rawValue
    case .landscapeLeft:
        return GMVDetectorImageOrientation.topRight.rawValue
    case .landscapeRight:
        return GMVDetectorImageOrientation.bottomLeft.rawValue
    default:
        // 默认竖屏方向
        return GMVDetectorImageOrientation.topLeft.rawValue
    }
}

2. 调用检测器时传入方向参数

在captureOutput中调用Google检测器时,把方向作为option传入,而不是传nil:

// 替换原来的检测代码
let gmvDetectOptions = [GMVDetectorImageOrientation: gmvOrientation(from: UIDevice.current.orientation)]
if let faces = GfaceDetector?.features(in: Gimage, options: gmvDetectOptions) as? [GMVFaceFeature] {
    print("GFace count: \(faces.count)")
    // 后续处理人脸逻辑...
}

3. 同步相机连接方向(关键)

还要确保相机的捕获方向和设备方向一致,在初始化AVCaptureSession的输出时添加这段代码:

if let videoConnection = videoDataOutput.connection(with: .video) {
    if videoConnection.isVideoOrientationSupported {
        videoConnection.videoOrientation = AVCaptureVideoOrientation(rawValue: UIDevice.current.orientation.rawValue)!
    }
}

问题B:顺时针旋转UIImage90度(不修改UIImageView)

如果需要手动旋转图像而非依赖检测器的方向参数,可以用以下函数直接修改UIImage本身:

func rotateImageClockwise90(_ image: UIImage) -> UIImage? {
    guard let cgImage = image.cgImage else { return nil }
    
    // 计算旋转后的尺寸
    let rotationTransform = CGAffineTransform(rotationAngle: CGFloat.pi / 2)
    let rotatedRect = CGRect(origin: .zero, size: image.size).applying(rotationTransform)
    
    UIGraphicsBeginImageContextWithOptions(rotatedRect.size, false, image.scale)
    guard let context = UIGraphicsGetCurrentContext() else { return nil }
    
    // 平移+旋转画布,再绘制原图
    context.translateBy(x: rotatedRect.size.width/2, y: rotatedRect.size.height/2)
    context.rotate(by: CGFloat.pi / 2)
    context.draw(cgImage, in: CGRect(x: -image.size.width/2, y: -image.size.height/2, width: image.size.width, height: image.size.height))
    
    let rotatedImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    
    return rotatedImage
}

使用时直接替换原图像:

let ciImage1 = CIImage(cvImageBuffer: pixelBuffer!, options: attachments as! [String : Any]?)
let originalImage = UIImage(ciImage: ciImage1)
// 旋转后再传入检测器
if let rotatedImage = rotateImageClockwise90(originalImage) {
    // 此时图像已直立,直接传topLeft方向
    let gmvOptions = [GMVDetectorImageOrientation: GMVDetectorImageOrientation.topLeft.rawValue]
    let Gfaces = GfaceDetector?.features(in: rotatedImage, options: gmvOptions) as? [GMVFaceFeature]
}

额外排查建议

  1. 调整最小人脸尺寸:你设置的GMVDetectorFaceMinSize: 0.15可能过小,相机流中人脸占比如果低于这个阈值会被忽略,可以尝试调到0.2或0.25。
  2. 统一像素格式:Google API对某些像素格式支持有限,建议设置相机输出格式为通用的BGRA:
videoDataOutput.videoSettings = [kCVPixelBufferPixelFormatTypeKey as String: kCVPixelFormatType_32BGRA]
  1. 避免帧处理阻塞:确保captureOutput在后台队列执行(默认配置是对的),不要在检测逻辑中做主线程耗时操作。

内容的提问来源于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:33:22