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] }
额外排查建议
- 调整最小人脸尺寸:你设置的
GMVDetectorFaceMinSize: 0.15可能过小,相机流中人脸占比如果低于这个阈值会被忽略,可以尝试调到0.2或0.25。 - 统一像素格式:Google API对某些像素格式支持有限,建议设置相机输出格式为通用的BGRA:
videoDataOutput.videoSettings = [kCVPixelBufferPixelFormatTypeKey as String: kCVPixelFormatType_32BGRA]
- 避免帧处理阻塞:确保
captureOutput在后台队列执行(默认配置是对的),不要在检测逻辑中做主线程耗时操作。
内容的提问来源于stack exchange,提问作者coder
相关产品推荐
相关产品推荐

