您可以使用机器学习套件检测图片和视频中的人脸。
试试看
- 您可以试用示例应用, 查看此 API 的用法示例。
- 使用 亲自试用代码 Codelab。
准备工作
- 在 Podfile 中添加以下机器学习套件 Pod:
pod 'GoogleMLKit/FaceDetection', '3.2.0'
- 安装或更新项目的 Pod 之后,使用 Xcode 项目的
.xcworkspace
。Xcode 12.4 或更高版本支持机器学习套件。
输入图片准则
对于人脸识别,您使用的图片尺寸应至少为 480x360 像素。 为了使机器学习套件准确检测人脸,输入图片必须包含人脸 用足够像素数据表示的图片。一般来说,您需要的 至少应为 100x100 像素如果您想检测 人脸轮廓线,机器学习套件需要更高的分辨率输入: 尺寸至少应为 200x200 像素。
如果在实时应用中检测人脸,您可能还需要 考虑输入图片的整体尺寸。尺寸较小的图片 因此为了缩短延迟时间,请以较低分辨率捕获图片 遵守上述准确性要求,并确保 正文的脸会占据图像的尽可能多的空间。另请参阅 提高实时性能的相关提示。
图片聚焦不佳也会影响准确性。如果不接受 结果,要求用户重新拍摄图片。
人脸相对于镜头的方向也会影响面部的 机器学习套件检测到的功能。请参阅 人脸检测概念。
1. 配置人脸检测器
在对图片应用人脸检测之前,如果您想更改 人脸检测器的默认设置,请使用FaceDetectorOptions
对象。您可以更改
以下设置:
设置 | |
---|---|
performanceMode |
fast (默认值)|accurate
在检测人脸时更注重速度还是准确性。 |
landmarkMode |
none (默认值)|all
是否尝试检测面部“特征点”:眼睛、 耳朵、鼻子、脸颊、嘴巴等所有已检测到的面部特征。 |
contourMode |
none (默认值)|all
是否检测面部特征的轮廓。轮廓线为 仅对图片中最突出的面孔进行检测。 |
classificationMode |
none (默认值)|all
是否将面部分为不同类别,例如“微笑” 以及“睁大眼睛”的程度 |
minFaceSize |
CGFloat (默认值:0.1 )
设置所需的最小面部大小,表示为 即头部的宽度与图片的宽度相等。 |
isTrackingEnabled |
false (默认值)|true
是否为面孔分配可用于跟踪的 ID 人脸识别。 请注意,启用轮廓检测后, 因此面部跟踪生成有用的结果。为此 为了提高检测速度,请勿同时启用 检测和面部跟踪。 |
例如,构建 FaceDetectorOptions
对象,如以下示例中所示:
Swift
// High-accuracy landmark detection and face classification let options = FaceDetectorOptions() options.performanceMode = .accurate options.landmarkMode = .all options.classificationMode = .all // Real-time contour detection of multiple faces // options.contourMode = .all
Objective-C
// High-accuracy landmark detection and face classification MLKFaceDetectorOptions *options = [[MLKFaceDetectorOptions alloc] init]; options.performanceMode = MLKFaceDetectorPerformanceModeAccurate; options.landmarkMode = MLKFaceDetectorLandmarkModeAll; options.classificationMode = MLKFaceDetectorClassificationModeAll; // Real-time contour detection of multiple faces // options.contourMode = MLKFaceDetectorContourModeAll;
2. 准备输入图片
如需检测图片中的人脸,请将图片作为UIImage
或
CMSampleBufferRef
传输至 FaceDetector
process(_:completion:)
或 results(in:)
方法:
使用 UIImage
或VisionImage
CMSampleBuffer
。
如果您使用 UIImage
,请按以下步骤操作:
- 使用
UIImage
创建一个VisionImage
对象。请务必指定正确的.orientation
。Swift
let image = VisionImage(image: UIImage) visionImage.orientation = image.imageOrientation
Objective-C
MLKVisionImage *visionImage = [[MLKVisionImage alloc] initWithImage:image]; visionImage.orientation = image.imageOrientation;
如果您使用 CMSampleBuffer
,请按以下步骤操作:
-
指定
CMSampleBuffer
。如需获取图片方向,请执行以下操作:
Swift
func imageOrientation( deviceOrientation: UIDeviceOrientation, cameraPosition: AVCaptureDevice.Position ) -> UIImage.Orientation { switch deviceOrientation { case .portrait: return cameraPosition == .front ? .leftMirrored : .right case .landscapeLeft: return cameraPosition == .front ? .downMirrored : .up case .portraitUpsideDown: return cameraPosition == .front ? .rightMirrored : .left case .landscapeRight: return cameraPosition == .front ? .upMirrored : .down case .faceDown, .faceUp, .unknown: return .up } }
Objective-C
- (UIImageOrientation) imageOrientationFromDeviceOrientation:(UIDeviceOrientation)deviceOrientation cameraPosition:(AVCaptureDevicePosition)cameraPosition { switch (deviceOrientation) { case UIDeviceOrientationPortrait: return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationLeftMirrored : UIImageOrientationRight; case UIDeviceOrientationLandscapeLeft: return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationDownMirrored : UIImageOrientationUp; case UIDeviceOrientationPortraitUpsideDown: return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationRightMirrored : UIImageOrientationLeft; case UIDeviceOrientationLandscapeRight: return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationUpMirrored : UIImageOrientationDown; case UIDeviceOrientationUnknown: case UIDeviceOrientationFaceUp: case UIDeviceOrientationFaceDown: return UIImageOrientationUp; } }
- 使用
VisionImage
CMSampleBuffer
对象和方向:Swift
let image = VisionImage(buffer: sampleBuffer) image.orientation = imageOrientation( deviceOrientation: UIDevice.current.orientation, cameraPosition: cameraPosition)
Objective-C
MLKVisionImage *image = [[MLKVisionImage alloc] initWithBuffer:sampleBuffer]; image.orientation = [self imageOrientationFromDeviceOrientation:UIDevice.currentDevice.orientation cameraPosition:cameraPosition];
3. 获取 FaceDetector 的一个实例
获取 FaceDetector
的一个实例:
Swift
let faceDetector = FaceDetector.faceDetector(options: options)
Objective-C
MLKFaceDetector *faceDetector = [MLKFaceDetector faceDetectorWithOptions:options];
4. 处理图片
然后,将图片传递给process()
方法:
Swift
weak var weakSelf = self faceDetector.process(visionImage) { faces, error in guard let strongSelf = weakSelf else { print("Self is nil!") return } guard error == nil, let faces = faces, !faces.isEmpty else { // ... return } // Faces detected // ... }
Objective-C
[faceDetector processImage:image completion:^(NSArray<MLKFace *> *faces, NSError *error) { if (error != nil) { return; } if (faces.count > 0) { // Recognized faces } }];
5. 获取检测到的人脸的相关信息
如果人脸检测操作成功,人脸检测器将传递一个数组 一组Face
对象传递给完成处理程序。每个
Face
对象表示在图片中检测到的面孔。对于
您可以获取它在输入图像中的边界坐标,
您配置面部检测器查找的任何其他信息。例如:
Swift
for face in faces { let frame = face.frame if face.hasHeadEulerAngleX { let rotX = face.headEulerAngleX // Head is rotated to the uptoward rotX degrees } if face.hasHeadEulerAngleY { let rotY = face.headEulerAngleY // Head is rotated to the right rotY degrees } if face.hasHeadEulerAngleZ { let rotZ = face.headEulerAngleZ // Head is tilted sideways rotZ degrees } // If landmark detection was enabled (mouth, ears, eyes, cheeks, and // nose available): if let leftEye = face.landmark(ofType: .leftEye) { let leftEyePosition = leftEye.position } // If contour detection was enabled: if let leftEyeContour = face.contour(ofType: .leftEye) { let leftEyePoints = leftEyeContour.points } if let upperLipBottomContour = face.contour(ofType: .upperLipBottom) { let upperLipBottomPoints = upperLipBottomContour.points } // If classification was enabled: if face.hasSmilingProbability { let smileProb = face.smilingProbability } if face.hasRightEyeOpenProbability { let rightEyeOpenProb = face.rightEyeOpenProbability } // If face tracking was enabled: if face.hasTrackingID { let trackingId = face.trackingID } }
Objective-C
for (MLKFace *face in faces) { // Boundaries of face in image CGRect frame = face.frame; if (face.hasHeadEulerAngleX) { CGFloat rotX = face.headEulerAngleX; // Head is rotated to the upward rotX degrees } if (face.hasHeadEulerAngleY) { CGFloat rotY = face.headEulerAngleY; // Head is rotated to the right rotY degrees } if (face.hasHeadEulerAngleZ) { CGFloat rotZ = face.headEulerAngleZ; // Head is tilted sideways rotZ degrees } // If landmark detection was enabled (mouth, ears, eyes, cheeks, and // nose available): MLKFaceLandmark *leftEar = [face landmarkOfType:FIRFaceLandmarkTypeLeftEar]; if (leftEar != nil) { MLKVisionPoint *leftEarPosition = leftEar.position; } // If contour detection was enabled: MLKFaceContour *upperLipBottomContour = [face contourOfType:FIRFaceContourTypeUpperLipBottom]; if (upperLipBottomContour != nil) { NSArray<MLKVisionPoint *> *upperLipBottomPoints = upperLipBottomContour.points; if (upperLipBottomPoints.count > 0) { NSLog("Detected the bottom contour of the subject's upper lip.") } } // If classification was enabled: if (face.hasSmilingProbability) { CGFloat smileProb = face.smilingProbability; } if (face.hasRightEyeOpenProbability) { CGFloat rightEyeOpenProb = face.rightEyeOpenProbability; } // If face tracking was enabled: if (face.hasTrackingID) { NSInteger trackingID = face.trackingID; } }
面部轮廓的示例
启用人脸轮廓检测后, 检测到的每个面部特征。这些点表示 功能。请参阅人脸 检测概念,详细了解轮廓如何定义 代表性。
下图展示了这些点与人脸的对应关系,请点击 要放大的图片:
实时人脸检测
如果您想在实时应用中使用人脸检测,请按以下方法操作 实现最佳帧速率的准则:
请将人脸检测器配置为使用 面部轮廓检测或分类和特征点检测,但不能同时采用两者:
轮廓检测
地标检测
分类
特征点检测和分类
轮廓检测和特征点检测
轮廓检测和分类
轮廓检测、特征点检测和分类启用
fast
模式(默认启用)。建议以较低的分辨率捕获图片。但请注意 该 API 的图片尺寸要求
- 如需处理视频帧,请使用检测器的
results(in:)
同步 API。致电 此方法(可从 获取)AVCaptureVideoDataOutputSampleBufferDelegate
的captureOutput(_, didOutput:from:)
函数,用于同步获取指定视频的结果 帧。保留AVCaptureVideoDataOutput
的alwaysDiscardsLateVideoFrames
设置为true
,以限制对检测器的调用。如果新的 视频帧在检测器运行时可用,则会丢失。 - 如果您使用检测器的输出在图像上叠加显示 输入图片,首先从机器学习套件获取结果, 和叠加层。通过这种方式,您可以在显示屏上呈现 只对每个已处理的输入帧运行一次。请参阅 updatePreviewOverlayViewWithLastFrame 。