您可以使用机器学习套件检测图片和视频中的人脸。
准备工作
- 如果您尚未将 Firebase 添加到自己的应用中,请按照入门指南中的步骤执行此操作。
- 在 Podfile 中添加机器学习套件库:
pod 'Firebase/MLVision', '6.25.0' # If you want to detect face contours (landmark detection and classification # don't require this additional model): pod 'Firebase/MLVisionFaceModel', '6.25.0'
在安装或更新项目的 Pod 之后,请务必使用 Xcode 项目的.xcworkspace
打开该项目。 - 在您的应用中导入 Firebase:
Swift
import Firebase
Objective-C
@import Firebase;
输入图片指南
为了使机器学习套件准确检测人脸,输入图片必须包含由足够像素数据表示的人脸。通常,要在图片中检测的每张人脸应至少为 100x100 像素。如果要检测人脸轮廓,机器学习套件需要更高的分辨率输入:每张人脸应至少为 200x200 像素。
如果您是在实时应用中检测人脸,可能还需要考虑输入图片的整体尺寸。较小图片的处理速度相对较快,因此,为了减少延迟时间,请以较低的分辨率捕获图片(同时需满足上述人脸图片的精度要求),并确保主体的面部在图片中占尽可能大的部分。另请参阅提高实时性能的相关提示。
图片聚焦不良会影响准确性。如果您无法获得满意的结果,请尝试让用户重新捕获图片。
人脸相对于相机的方向也会影响机器学习套件检测的面部特征。请参阅人脸检测概念。
1. 配置人脸检测器
在对图片进行人脸检测之前,如果要更改人脸检测器的默认设置,请使用VisionFaceDetectorOptions
对象指定这些设置。您可以更改以下设置:
设置 | |
---|---|
performanceMode |
fast (默认)| accurate
在检测人脸时更注重速度还是准确性。 |
landmarkMode |
none (默认)| all
是否尝试识别检测到的所有人脸的“特征点”:眼睛、耳朵、鼻子、脸颊、嘴巴。 |
contourMode |
none (默认)| all
是否检测面部特征的轮廓。仅检测图片中最突出的人脸的轮廓。 |
classificationMode |
none (默认)| all
是否将人脸分为不同类别(例如“微笑”和“睁眼”)。 |
minFaceSize |
CGFloat (默认:0.1 )
需要检测的人脸的大小下限(相对于图片)。 |
isTrackingEnabled |
false (默认)| true
是否为人脸分配 ID,以用于跨图片跟踪人脸。 请注意,启用轮廓检测后,仅会检测一张人脸,因此人脸跟踪不会产生有用的结果。如需加快检测速度,请勿同时启用轮廓检测和人脸跟踪。 |
例如,如以下示例所示,构建 VisionFaceDetectorOptions
对象:
Swift
// High-accuracy landmark detection and face classification let options = VisionFaceDetectorOptions() options.performanceMode = .accurate options.landmarkMode = .all options.classificationMode = .all // Real-time contour detection of multiple faces let options = VisionFaceDetectorOptions() options.contourMode = .all
Objective-C
// High-accuracy landmark detection and face classification FIRVisionFaceDetectorOptions *options = [[FIRVisionFaceDetectorOptions alloc] init]; options.performanceMode = FIRVisionFaceDetectorPerformanceModeAccurate; options.landmarkMode = FIRVisionFaceDetectorLandmarkModeAll; options.classificationMode = FIRVisionFaceDetectorClassificationModeAll; // Real-time contour detection of multiple faces FIRVisionFaceDetectorOptions *options = [[FIRVisionFaceDetectorOptions alloc] init]; options.contourMode = FIRVisionFaceDetectorContourModeAll;
2. 运行人脸检测器
如需检测图片中的人脸,请将图片作为UIImage
或 CMSampleBufferRef
传递给 VisionFaceDetector
的 detect(in:)
方法:
- 获取
VisionFaceDetector
的一个实例:Swift
lazy var vision = Vision.vision() let faceDetector = vision.faceDetector(options: options)
Objective-C
FIRVision *vision = [FIRVision vision]; FIRVisionFaceDetector *faceDetector = [vision faceDetector]; // Or, to change the default settings: // FIRVisionFaceDetector *faceDetector = // [vision faceDetectorWithOptions:options];
-
使用
UIImage
或CMSampleBufferRef
创建一个VisionImage
对象。如需使用
UIImage
,请按以下步骤操作:- 在必要时旋转图片,以使其
imageOrientation
属性为.up
。 - 使用方向正确的
UIImage
创建一个VisionImage
对象。不要指定任何旋转方式元数据,必须使用默认值.topLeft
。Swift
let image = VisionImage(image: uiImage)
Objective-C
FIRVisionImage *image = [[FIRVisionImage alloc] initWithImage:uiImage];
如需使用
CMSampleBufferRef
,请按以下步骤操作:-
创建一个
VisionImageMetadata
对象,用其指定CMSampleBufferRef
缓冲区中所含图片数据的方向。如需获取图片方向,请运行以下代码:
Swift
func imageOrientation( deviceOrientation: UIDeviceOrientation, cameraPosition: AVCaptureDevice.Position ) -> VisionDetectorImageOrientation { switch deviceOrientation { case .portrait: return cameraPosition == .front ? .leftTop : .rightTop case .landscapeLeft: return cameraPosition == .front ? .bottomLeft : .topLeft case .portraitUpsideDown: return cameraPosition == .front ? .rightBottom : .leftBottom case .landscapeRight: return cameraPosition == .front ? .topRight : .bottomRight case .faceDown, .faceUp, .unknown: return .leftTop } }
Objective-C
- (FIRVisionDetectorImageOrientation) imageOrientationFromDeviceOrientation:(UIDeviceOrientation)deviceOrientation cameraPosition:(AVCaptureDevicePosition)cameraPosition { switch (deviceOrientation) { case UIDeviceOrientationPortrait: if (cameraPosition == AVCaptureDevicePositionFront) { return FIRVisionDetectorImageOrientationLeftTop; } else { return FIRVisionDetectorImageOrientationRightTop; } case UIDeviceOrientationLandscapeLeft: if (cameraPosition == AVCaptureDevicePositionFront) { return FIRVisionDetectorImageOrientationBottomLeft; } else { return FIRVisionDetectorImageOrientationTopLeft; } case UIDeviceOrientationPortraitUpsideDown: if (cameraPosition == AVCaptureDevicePositionFront) { return FIRVisionDetectorImageOrientationRightBottom; } else { return FIRVisionDetectorImageOrientationLeftBottom; } case UIDeviceOrientationLandscapeRight: if (cameraPosition == AVCaptureDevicePositionFront) { return FIRVisionDetectorImageOrientationTopRight; } else { return FIRVisionDetectorImageOrientationBottomRight; } default: return FIRVisionDetectorImageOrientationTopLeft; } }
然后,创建元数据对象:
Swift
let cameraPosition = AVCaptureDevice.Position.back // Set to the capture device you used. let metadata = VisionImageMetadata() metadata.orientation = imageOrientation( deviceOrientation: UIDevice.current.orientation, cameraPosition: cameraPosition )
Objective-C
FIRVisionImageMetadata *metadata = [[FIRVisionImageMetadata alloc] init]; AVCaptureDevicePosition cameraPosition = AVCaptureDevicePositionBack; // Set to the capture device you used. metadata.orientation = [self imageOrientationFromDeviceOrientation:UIDevice.currentDevice.orientation cameraPosition:cameraPosition];
- 使用
CMSampleBufferRef
对象和旋转方式元数据创建一个VisionImage
对象:Swift
let image = VisionImage(buffer: sampleBuffer) image.metadata = metadata
Objective-C
FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer]; image.metadata = metadata;
- 在必要时旋转图片,以使其
- 然后,将图片传递给
detect(in:)
方法:Swift
faceDetector.process(visionImage) { faces, error in guard error == nil, let faces = faces, !faces.isEmpty else { // ... return } // Faces detected // ... }
Objective-C
[faceDetector detectInImage:image completion:^(NSArray<FIRVisionFace *> *faces, NSError *error) { if (error != nil) { return; } else if (faces != nil) { // Recognized faces } }];
3. 获取检测到的人脸的相关信息
如果人脸检测操作成功,人脸检测器会向完成处理程序传递一组VisionFace
对象。每个 VisionFace
对象都代表在图片中检测到的一张人脸。对于每张人脸,您可以获取它在输入图片中的边界坐标,以及您已配置人脸检测器所要查找的任何其他信息。例如:
Swift
for face in faces { let frame = face.frame if face.hasHeadEulerAngleY { let rotY = face.headEulerAngleY // Head is rotated to the right rotY degrees } if face.hasHeadEulerAngleZ { let rotZ = face.headEulerAngleZ // Head is rotated upward 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 (FIRVisionFace *face in faces) { // Boundaries of face in image CGRect frame = face.frame; 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): FIRVisionFaceLandmark *leftEar = [face landmarkOfType:FIRFaceLandmarkTypeLeftEar]; if (leftEar != nil) { FIRVisionPoint *leftEarPosition = leftEar.position; } // If contour detection was enabled: FIRVisionFaceContour *upperLipBottomContour = [face contourOfType:FIRFaceContourTypeUpperLipBottom]; if (upperLipBottomContour != nil) { NSArray<FIRVisionPoint *> *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 的图片尺寸要求。
- 限制检测器的调用次数。如果在检测器运行时有新的视频帧可用,请丢弃该帧。
- 如果要将检测器的输出作为图形叠加在输入图片上,请先从机器学习套件获取结果,然后在一个步骤中完成图片的呈现和叠加。采用这一方法,每个输入帧只需在显示表面呈现一次。如需查看示例,请参阅示例应用中的 previewOverlayView 和 FIRDetectionOverlayView 类。