借助 MediaPipe Face Markerer 任务,您可以检测图片和视频中的人脸特征点和面部表情。您可以使用此任务来识别人脸表情、应用脸部滤镜和效果,以及创建虚拟头像。此任务使用可处理单个图片、视频或连续图片流的机器学习 (ML) 模型。该任务会输出 3D 面部地标、融合变形得分(表示面部表情的系数),以实时推断详细的面部表面,以及转换矩阵,以执行效果渲染所需的转换。
这些说明中介绍的代码示例可在 GitHub 上找到。您可以查看此 Web 演示,了解此任务的实际运作方式。如需详细了解此任务的功能、模型和配置选项,请参阅概览。
代码示例
MediaPipe Tasks 示例代码是对适用于 iOS 的 Face Landmarker 应用的基本实现。该示例使用实体 iOS 设备上的摄像头检测连续视频流中的人脸地标。该应用还可以检测设备图库中的图片和视频中的人脸地标。
您可以将该应用用作您自己的 iOS 应用的起点,也可以在修改现有应用时参考该应用。Face Landmarker 示例代码托管在 GitHub 上。
下载代码
以下说明介绍了如何使用 git 命令行工具创建示例代码的本地副本。
如需下载示例代码,请执行以下操作:
使用以下命令克隆 git 代码库:
git clone https://github.com/google-ai-edge/mediapipe-samples
(可选)将您的 Git 实例配置为使用稀疏签出,以便只具有 Face Markerer 示例应用的文件:
cd mediapipe git sparse-checkout init --cone git sparse-checkout set examples/face_landmarker/ios
创建示例代码的本地版本后,您可以安装 MediaPipe 任务库,使用 Xcode 打开项目并运行应用。如需了解相关说明,请参阅 适用于 iOS 的设置指南。
关键组件
以下文件包含 Face Landmarker 示例应用的重要代码:
- FaceLandmarkerService.swift:初始化 Face Landmarker,处理模型选择,并对输入数据运行推理。
- CameraViewController.swift:为实时摄像头画面输入模式实现界面,并直观呈现结果。
- MediaLibraryViewController.swift:实现静态图片和视频文件输入模式的界面并直观呈现结果。
设置
本部分介绍了设置开发环境和代码项目以使用 Face Landmarker 的关键步骤。如需了解如何设置开发环境以使用 MediaPipe 任务(包括平台版本要求)的一般信息,请参阅 适用于 iOS 的设置指南。
依赖项
Face Landmarker 使用 MediaPipeTasksVision
库,该库必须使用 CocoaPods 安装。该库与 Swift 和 Objective-C 应用兼容,并且无需任何额外的语言专用设置。
如需了解如何在 macOS 上安装 CocoaPods,请参阅 CocoaPods 安装指南。如需了解如何创建包含应用所需 pod 的 Podfile
,请参阅使用 CocoaPods。
使用以下代码在 Podfile
中添加 MediaPipeTasksVision
pod:
target 'MyFaceLandmarkerApp' do
use_frameworks!
pod 'MediaPipeTasksVision'
end
如果您的应用包含单元测试目标,请参阅 iOS 设置指南,详细了解如何设置 Podfile
。
型号
MediaPipe Face Landmarker 任务需要与此任务兼容的训练模型软件包。如需详细了解人脸特征点分析程序的可用训练模型,请参阅任务概览“模型”部分。
选择并下载模型,然后使用 Xcode 将其添加到您的项目目录。 如需了解如何向 Xcode 项目添加文件,请参阅管理 Xcode 项目中的文件和文件夹。
使用 BaseOptions.modelAssetPath
属性指定 app bundle 中的模型路径。如需查看代码示例,请参阅下一部分。
创建任务
您可以通过调用人脸特征点器任务之一来创建该任务。FaceLandmarker(options:)
初始化程序接受配置选项的值。
如果您不需要使用自定义配置选项初始化人脸关键点检测器,可以使用 FaceLandmarker(modelPath:)
初始化程序使用默认选项创建人脸关键点检测器。如需详细了解配置选项,请参阅配置概览。
人脸地标任务支持 3 种输入数据类型:静态图片、视频文件和实时视频流。默认情况下,FaceLandmarker(modelPath:)
会为静态图片初始化任务。如果您希望将任务初始化以处理视频文件或实时视频串流,请使用 FaceLandmarker(options:)
指定视频或直播视频流运行模式。实时流式传输模式还需要额外的 faceLandmarkerLiveStreamDelegate
配置选项,这样,人脸特征点工具才能以异步方式将人脸特征点器结果发送给代理。
选择与您的运行模式对应的标签页,了解如何创建任务并运行推理。
Swift
Image
import MediaPipeTasksVision let modelPath = Bundle.main.path( forResource: "face_landmarker", ofType: "task") let options = FaceLandmarkerOptions() options.baseOptions.modelAssetPath = modelPath options.runningMode = .image options.minFaceDetectionConfidence = minFaceDetectionConfidence options.minFacePresenceConfidence = minFacePresenceConfidence options.minTrackingConfidence = minTrackingConfidence options.numFaces = numFaces let faceLandmarker = try FaceLandmarker(options: options)
视频
import MediaPipeTasksVision let modelPath = Bundle.main.path( forResource: "face_landmarker", ofType: "task") let options = FaceLandmarkerOptions() options.baseOptions.modelAssetPath = modelPath options.runningMode = .video options.minFaceDetectionConfidence = minFaceDetectionConfidence options.minFacePresenceConfidence = minFacePresenceConfidence options.minTrackingConfidence = minTrackingConfidence options.numFaces = numFaces let faceLandmarker = try FaceLandmarker(options: options)
直播
import MediaPipeTasksVision // Class that conforms to the `FaceLandmarkerLiveStreamDelegate` protocol and // implements the method that the face landmarker calls once it finishes // performing face landmark detection in each input frame. class FaceLandmarkerResultProcessor: NSObject, FaceLandmarkerLiveStreamDelegate { func faceLandmarker( _ faceLandmarker: FaceLandmarker, didFinishDetection result: FaceLandmarkerResult?, timestampInMilliseconds: Int, error: Error?) { // Process the face landmarker result or errors here. } } let modelPath = Bundle.main.path( forResource: "face_landmarker", ofType: "task") let options = FaceLandmarkerOptions() options.baseOptions.modelAssetPath = modelPath options.runningMode = .liveStream options.minFaceDetectionConfidence = minFaceDetectionConfidence options.minFacePresenceConfidence = minFacePresenceConfidence options.minTrackingConfidence = minTrackingConfidence options.numFaces = numFaces // Assign an object of the class to the `faceLandmarkerLiveStreamDelegate` // property. let processor = FaceLandmarkerResultProcessor() options.faceLandmarkerLiveStreamDelegate = processor let faceLandmarker = try FaceLandmarker(options: options)
Objective-C
Image
@import MediaPipeTasksVision; NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"face_landmarker" ofType:@"task"]; MPPFaceLandmarkerOptions *options = [[MPPFaceLandmarkerOptions alloc] init]; options.baseOptions.modelAssetPath = modelPath; options.runningMode = MPPRunningModeImage; options.minFaceDetectionConfidence = minFaceDetectionConfidence; options.minFacePresenceConfidence = minFacePresenceConfidence; options.minTrackingConfidence = minTrackingConfidence; options.numFaces = numFaces; MPPFaceLandmarker *faceLandmarker = [[MPPFaceLandmarker alloc] initWithOptions:options error:nil];
视频
@import MediaPipeTasksVision; NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"face_landmarker" ofType:@"task"]; MPPFaceLandmarkerOptions *options = [[MPPFaceLandmarkerOptions alloc] init]; options.baseOptions.modelAssetPath = modelPath; options.runningMode = MPPRunningModeVideo; options.minFaceDetectionConfidence = minFaceDetectionConfidence; options.minFacePresenceConfidence = minFacePresenceConfidence; options.minTrackingConfidence = minTrackingConfidence; options.numFaces = numFaces; MPPFaceLandmarker *faceLandmarker = [[MPPFaceLandmarker alloc] initWithOptions:options error:nil];
直播
@import MediaPipeTasksVision; // Class that conforms to the `MPPFaceLandmarkerLiveStreamDelegate` protocol // and implements the method that the face landmarker calls once it finishes // performing face landmark detection in each input frame. @interface APPFaceLandmarkerResultProcessor : NSObject@end @implementation APPFaceLandmarkerResultProcessor - (void)faceLandmarker:(MPPFaceLandmarker *)faceLandmarker didFinishDetectionWithResult:(MPPFaceLandmarkerResult *)faceLandmarkerResult timestampInMilliseconds:(NSInteger)timestampInMilliseconds error:(NSError *)error { // Process the face landmarker result or errors here. } @end NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"face_landmarker" ofType:@"task"]; MPPFaceLandmarkerOptions *options = [[MPPFaceLandmarkerOptions alloc] init]; options.baseOptions.modelAssetPath = modelPath; options.runningMode = MPPRunningModeLiveStream; options.minFaceDetectionConfidence = minFaceDetectionConfidence; options.minFacePresenceConfidence = minFacePresenceConfidence; options.minTrackingConfidence = minTrackingConfidence; options.numFaces = numFaces; // Assign an object of the class to the `faceLandmarkerLiveStreamDelegate` // property. APPFaceLandmarkerResultProcessor *processor = [APPFaceLandmarkerResultProcessor new]; options.faceLandmarkerLiveStreamDelegate = processor; MPPFaceLandmarker *faceLandmarker = [[MPPFaceLandmarker alloc] initWithOptions:options error:nil];
注意:如果您使用视频模式或直播模式,Face Landmarker 会使用跟踪功能,以避免在每个帧上触发检测模型,这有助于缩短延迟时间。
配置选项
此任务针对 iOS 应用提供了以下配置选项:
选项名称 | 说明 | 值范围 | 默认值 |
---|---|---|---|
runningMode |
设置任务的运行模式。人脸特征点标记器有三种模式:
IMAGE:用于单张图片输入的模式。 VIDEO:视频已解码帧的模式。 LIVE_STREAM:输入数据实时流式传输的模式,例如来自摄像头的模式。 在此模式下,必须将 `faceLandmarkerLiveStreamDelegate` 设置为实现 `FaceLandmarkerLiveStreamDelegate` 的类的实例,以便异步接收执行人脸标志检测的结果。 |
{RunningMode.image, RunningMode.video, RunningMode.liveStream} | {RunningMode.image} |
numFaces |
人脸特征点工具可以检测到的人脸数量上限。仅当 numFaces 设置为 1 时才应用平滑。 | 整数 > 0 | 1 |
minFaceDetectionConfidence |
人脸检测被视为成功所需的最低置信度得分。 | 浮点数 [0.0,1.0] | 0.5 |
minFacePresenceConfidence |
人脸标志检测中人脸存在分数的最低置信度分数。 | 浮点数 [0.0,1.0] | 0.5 |
minTrackingConfidence |
人脸跟踪被视为成功所需的最低置信度得分。 | 浮点数 [0.0,1.0] | 0.5 |
outputFaceBlendshapes |
指定 FaceMarkerer 是否输出人脸融合变形。脸部混合形状用于渲染 3D 脸部模型。 | Bool | false |
outputFacialTransformationMatrixes |
FaceLandmarker 是否输出面部转换矩阵。 FaceLandmarker 使用矩阵将面部地标从规范化人脸模型转换为检测到的面部,以便用户对检测到的地标应用效果。 | Bool | false |
将运行模式设置为 LIVE_STREAM
时,Face Landmarker 需要额外的 faceLandmarkerLiveStreamDelegate
配置选项,以便 Face Landmarker 异步提供人脸特征点检测结果。代理必须实现 faceLandmarker(_:didFinishDetection:timestampInMilliseconds:error:)
方法,Face Landmarker 会在处理对每个帧执行人脸地标检测的结果后调用该方法。
选项名称 | 说明 | 值范围 | 默认值 |
---|---|---|---|
faceLandmarkerLiveStreamDelegate |
让 Face Landmarker 能够在直播模式下异步接收执行人脸特征点检测的结果。将实例设置为此属性的类必须实现 faceLandmarker(_:didFinishDetection:timestampInMilliseconds:error:) 方法。 |
不适用 | 未设置 |
准备数据
您需要先将输入图片或帧转换为 MPImage
对象,然后才能将其传递给人脸地标定位器。MPImage
支持不同类型的 iOS 图片格式,并且可以在任何运行模式下使用这些格式进行推理。如需详细了解 MPImage
,请参阅 MPImage API。
根据您的用例和应用所需的运行模式选择 iOS 映像格式。MPImage
接受 UIImage
、CVPixelBuffer
和 CMSampleBuffer
iOS 映像格式。
UIImage
UIImage
格式非常适合以下运行模式:
图片:应用软件包、用户图库或文件系统中格式为
UIImage
图片的图片可以转换为MPImage
对象。视频:使用 AVAssetImageGenerator 将视频帧提取为 CGImage 格式,然后将其转换为
UIImage
图片。
Swift
// Load an image on the user's device as an iOS `UIImage` object. // Convert the `UIImage` object to a MediaPipe's Image object having the default // orientation `UIImage.Orientation.up`. let image = try MPImage(uiImage: image)
Objective-C
// Load an image on the user's device as an iOS `UIImage` object. // Convert the `UIImage` object to a MediaPipe's Image object having the default // orientation `UIImageOrientationUp`. MPImage *image = [[MPPImage alloc] initWithUIImage:image error:nil];
该示例使用默认的 UIImage.Orientation.Up 方向初始化 MPImage
。您可以使用任何受支持的 UIImage.Orientation 值初始化 MPImage
。人脸特征点工具不支持 .upMirrored
、.downMirrored
、.leftMirrored
、.rightMirrored
等镜像方向。
如需详细了解 UIImage
,请参阅 UIImage Apple 开发者文档。
CVPixelBuffer
CVPixelBuffer
格式非常适合生成帧并使用 iOS CoreImage 框架进行处理的应用。
CVPixelBuffer
格式非常适合以下运行模式:
图片:在图片运行模式下,使用 iOS 的
CoreImage
框架进行一些处理后生成CVPixelBuffer
图片的应用可以发送到人脸地标定位器。视频:可以将视频帧转换为
CVPixelBuffer
格式进行处理,然后在视频模式下将其发送到人脸特征点标记器。直播:使用 iOS 相机生成帧的应用可能会先转换为
CVPixelBuffer
格式进行处理,然后再以直播模式发送到人脸地标检测器。
Swift
// Obtain a CVPixelBuffer. // Convert the `CVPixelBuffer` object to a MediaPipe's Image object having the default // orientation `UIImage.Orientation.up`. let image = try MPImage(pixelBuffer: pixelBuffer)
Objective-C
// Obtain a CVPixelBuffer. // Convert the `CVPixelBuffer` object to a MediaPipe's Image object having the // default orientation `UIImageOrientationUp`. MPImage *image = [[MPPImage alloc] initWithUIImage:image error:nil];
如需详细了解 CVPixelBuffer
,请参阅 CVPixelBuffer Apple 开发者文档。
CMSampleBuffer
CMSampleBuffer
格式用于存储统一媒体类型的媒体样本,非常适合直播运行模式。iOS 摄像头的实时帧由 iOS AVCaptureVideoDataOutput 以 CMSampleBuffer
格式异步传送。
Swift
// Obtain a CMSampleBuffer. // Convert the `CMSampleBuffer` object to a MediaPipe's Image object having the default // orientation `UIImage.Orientation.up`. let image = try MPImage(sampleBuffer: sampleBuffer)
Objective-C
// Obtain a `CMSampleBuffer`. // Convert the `CMSampleBuffer` object to a MediaPipe's Image object having the // default orientation `UIImageOrientationUp`. MPImage *image = [[MPPImage alloc] initWithSampleBuffer:sampleBuffer error:nil];
如需详细了解 CMSampleBuffer
,请参阅 CMSampleBuffer Apple 开发者文档。
运行任务
如需运行人脸特征点标记器,请使用特定于所分配的运行模式的 detect()
方法:
- 静态图片:
detect(image:)
- 视频:
detect(videoFrame:timestampInMilliseconds:)
- 直播:
detectAsync(image:timestampInMilliseconds:)
以下代码示例展示了如何在这些不同的运行模式下运行 Face Landmarker 的基本示例:
Swift
Image
let result = try faceLandmarker.detect(image: image)
视频
let result = try faceLandmarker.detect( videoFrame: image, timestampInMilliseconds: timestamp)
直播
try faceLandmarker.detectAsync( image: image, timestampInMilliseconds: timestamp)
Objective-C
Image
MPPFaceLandmarkerResult *result = [faceLandmarker detectImage:image error:nil];
视频
MPPFaceLandmarkerResult *result = [faceLandmarker detectVideoFrame:image timestampInMilliseconds:timestamp error:nil];
直播
BOOL success = [faceLandmarker detectAsyncImage:image timestampInMilliseconds:timestamp error:nil];
人脸特征点工具代码示例更详细地展示了以上每种模式的实现:detect(image:)
、detect(videoFrame:timestampInMilliseconds:)
和 detectAsync(image:timestampInMilliseconds:)
。示例代码允许用户在处理模式之间切换,但您的用例可能不需要这样做。
请注意以下几点:
在视频模式或直播模式下运行时,您还必须向 Face Landmarker 任务提供输入帧的时间戳。
在图片或视频模式下运行时,Face Landmarker 任务会阻塞当前线程,直到其处理完输入图片或帧。为避免阻塞当前线程,请使用 iOS Dispatch 或 NSOperation 框架在后台线程中执行处理。如果您的应用是使用 Swift 创建的,您还可以使用 Swift 并发进行后台线程执行。
在直播模式下运行时,人脸地标任务会立即返回,并且不会阻塞当前线程。它会在处理每个输入帧后,使用人脸地标检测结果调用
faceLandmarker(_:didFinishDetection:timestampInMilliseconds:error:)
方法。人脸地标定位器会在专用串行调度队列上异步调用此方法。如需在界面上显示结果,请在处理结果后将结果调度到主队列。
处理和显示结果
运行推理后,人脸地标检测器会返回一个 FaceLandmarkerResult
,其中包含每个检测到的人脸的面部网格,以及每个人脸地标的坐标。(可选)结果对象还可以包含表示面部表情的混合形状,以及用于对检测到的地标应用面部效果的面部变换矩阵。
以下是此任务的输出数据示例:
FaceLandmarkerResult:
face_landmarks:
NormalizedLandmark #0:
x: 0.5971359014511108
y: 0.485361784696579
z: -0.038440968841314316
NormalizedLandmark #1:
x: 0.3302789330482483
y: 0.29289937019348145
z: -0.09489090740680695
... (478 landmarks for each face)
face_blendshapes:
browDownLeft: 0.8296722769737244
browDownRight: 0.8096957206726074
browInnerUp: 0.00035583582939580083
browOuterUpLeft: 0.00035752105759456754
... (52 blendshapes for each face)
facial_transformation_matrixes:
[9.99158978e-01, -1.23036895e-02, 3.91213447e-02, -3.70770246e-01]
[1.66496094e-02, 9.93480563e-01, -1.12779640e-01, 2.27719707e+01]
...
下图显示了任务输出的可视化结果:
Face Landmarker 示例代码演示了如何显示任务返回的结果,如需了解详情,请参阅 FaceOverlay.swift。