通过 Image Segmenter 任务,您可以根据预定义的 类别,以及应用背景模糊等视觉效果。这些 说明了如何在 iOS 应用中使用图像分割器。
您可在 GitHub。
您可以通过查看网页 演示。 如需详细了解功能、模型和配置选项 请参阅 概览。
代码示例
MediaPipe Tasks 代码示例包含 iOS 版 Image Segmenter 应用。
该示例实现了可输出类别遮罩的图片分割器。它使用 将相机在 iOS 实体设备上进行实时图像分割 或设备图库中的图片和视频
您可以以此为基础来创建自己的 iOS 应用,也可以作为参考 对现有应用进行了修改。图片分割器示例代码托管在 GitHub。
下载代码
以下说明介绍了如何创建示例的本地副本 使用 git 命令行工具运行 git 代码库。
如需下载示例代码,请执行以下操作:
使用以下命令克隆 git 代码库:
git clone https://github.com/google-ai-edge/mediapipe-samples/
(可选)配置您的 git 实例以使用稀疏检出,这样您 只有 Image Segmenter 示例应用的文件:
cd mediapipe git sparse-checkout init --cone git sparse-checkout set examples/image_segmentation/ios/
创建示例代码的本地版本后,您可以安装 MediaPipe 任务库,使用 Xcode 打开项目并运行应用。对于 请参阅 iOS 设置指南。
关键组件
以下文件包含图像分割器示例的关键代码 应用:
- ImageSegmenterService.swift: 初始化图像分割器、处理模型选择并运行 根据输入数据进行推理。
- CameraViewController.swift: 实现实时摄像头画面输入模式的界面,并直观呈现 结果。
- MediaLibraryViewController.swift 实现静态图片和视频文件输入模式的界面,并 直观呈现结果
设置
本部分介绍了设置开发环境和 代码项目使用 Image Segmenter。有关如何设置 用于使用 MediaPipe 任务(包括平台版本)的开发环境 要求,请参阅 iOS 设置指南。
依赖项
Image Segmenter 使用 MediaPipeTasksVision
库,您必须安装该库
使用 CocoaPods 构建容器。该库与 Swift 和 Objective-C 应用兼容
并且不需要任何额外的语言相关设置。
如需了解如何在 macOS 上安装 CocoaPods,请参阅 CocoaPods
安装指南。
如需了解如何创建包含必要 Pod 的 Podfile
,请参阅
请参阅使用
CocoaPods。
使用以下代码在 Podfile
中添加 MediaPipeTasksVision pod:
target 'MyImageSegmenterApp' do
use_frameworks!
pod 'MediaPipeTasksVision'
end
如果您的应用包含单元测试目标,请参阅应用的设置指南
iOS 设备,详细了解如何设置
您的Podfile
。
型号
MediaPipe Image Segmenter 任务需要一个与 此任务。如需详细了解适用于 Kubernetes 的 Image Segmenter,请参阅任务概览模型 部分。
选择并下载模型,然后使用 Xcode 将其添加到您的项目目录。 有关如何向 Xcode 项目添加文件的说明,请参阅管理 Xcode 中的文件和文件夹 项目。
使用 BaseOptions.modelAssetPath
属性指定模型的路径
。如需查看代码示例,请参阅下一部分。
创建任务
您可以通过调用图像分割器任务之一来创建该任务。通过
ImageSegmenter(options:)
初始化程序接受配置的值
选项。
如果您不需要使用自定义配置初始化的图像分割器
可以使用 ImageSegmenter(modelPath:)
初始化程序创建
使用默认选项的图像分割器。如需详细了解配置
选项,请参阅配置概览。
Image Segmenter 任务支持 3 种输入数据类型:静态图片、视频文件
和直播视频流默认情况下,ImageSegmenter(modelPath:)
会初始化
执行任务。如果您希望将任务初始化以处理视频
文件或直播视频串流,请使用 ImageSegmenter(options:)
来指定视频
或实时流式传输模式直播模式还要求
imageSegmenterLiveStreamDelegate
配置选项,它启用
图像分割器,用于向受托人传送图像分割结果
异步执行。
选择与运行模式对应的标签页,了解如何创建任务 并进行推理。
Swift
映像
import MediaPipeTasksVision let modelPath = Bundle.main.path(forResource: "model", ofType: "tflite") let options = ImageSegmenterOptions() options.baseOptions.modelAssetPath = modelPath options.runningMode = .image options.shouldOutputCategoryMask = true options.shouldOutputConfidenceMasks = false let imageSegmenter = try ImageSegmenter(options: options)
视频
import MediaPipeTasksVision let modelPath = Bundle.main.path(forResource: "model", ofType: "tflite") let options = ImageSegmenterOptions() options.baseOptions.modelAssetPath = modelPath options.runningMode = .video options.shouldOutputCategoryMask = true options.shouldOutputConfidenceMasks = false let imageSegmenter = try ImageSegmenter(options: options)
直播
import MediaPipeTasksVision // Class that conforms to the `imageSegmenterLiveStreamDelegate` protocol and // implements the method that the image segmenter calls once it finishes // performing segmentation of each input frame. class ImageSegmenterResultProcessor: NSObject, ImageSegmenterLiveStreamDelegate { func imageSegmenter( _ imageSegmenter: ImageSegmenter, didFinishSegmentation result: ImageSegmenterResult?, timestampInMilliseconds: Int, error: Error?) { // Process the image segmentation result or errors here. } } let modelPath = Bundle.main.path(forResource: "model", ofType: "tflite") let options = ImageSegmenterOptions() options.baseOptions.modelAssetPath = modelPath options.runningMode = .liveStream options.shouldOutputCategoryMask = true options.shouldOutputConfidenceMasks = false // Set `imageSegmenterLiveStreamDelegate` to the object of the class that // confirms to the `ImageSegmenterLiveStreamDelegate` protocol. let processor = ImageSegmenterResultProcessor() options.imageSegmenterLiveStreamDelegate = processor let imageSegmenter = try ImageSegmenter(options: options)
Objective-C
映像
@import MediaPipeTasksVision; NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"model" ofType:@"tflite"]; MPPImageSegmenterOptions *options = [[MPPImageSegmenterOptions alloc] init]; options.baseOptions.modelAssetPath = modelPath; options.runningMode = MPPRunningModeImage; options.shouldOutputCategoryMask = YES; options.shouldOutputConfidenceMasks = NO; MPPImageSegmenter *imageSegmenter = [[MPPImageSegmenter alloc] initWithOptions:options error:nil];
视频
@import MediaPipeTasksVision; NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"model" ofType:@"tflite"]; MPPImageSegmenterOptions *options = [[MPPImageSegmenterOptions alloc] init]; options.baseOptions.modelAssetPath = modelPath; options.runningMode = MPPRunningModeVideo; options.shouldOutputCategoryMask = YES; options.shouldOutputConfidenceMasks = NO; MPPImageSegmenter *imageSegmenter = [[MPPImageSegmenter alloc] initWithOptions:options error:nil];
直播
@import MediaPipeTasksVision; // Class that conforms to the `MPPImageSegmenterLiveStreamDelegate` protocol // and implements the method that the image segmenter calls once it finishes // performing segmentation of each input frame. @interface APPImageSegmenterResultProcessor : NSObject@end @implementation APPImageSegmenterResultProcessor - (void)imageSegmenter:(MPPImageSegmenter *)imageSegmenter didFinishSegmentationWithResult:(MPPImageSegmenterResult *)imageSegmenterResult timestampInMilliseconds:(NSInteger)timestampInMilliseconds error:(NSError *)error { // Process the image segmentation result or errors here. } @end NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"model" ofType:@"tflite"]; MPPImageSegmenterOptions *options = [[MPPImageSegmenterOptions alloc] init]; options.baseOptions.modelAssetPath = modelPath; options.runningMode = MPPRunningModeLiveStream; options.shouldOutputCategoryMask = YES; options.shouldOutputConfidenceMasks = NO; // Set `imageSegmenterLiveStreamDelegate` to the object of the class that // confirms to the `MPPImageSegmenterLiveStreamDelegate` protocol. APPImageSegmenterResultProcessor *processor = [APPImageSegmenterResultProcessor new]; options.imageSegmenterLiveStreamDelegate = processor; MPPImageSegmenter *imageSegmenter = [[MPPImageSegmenter alloc] initWithOptions:options error:nil];
图片分割器示例代码实现允许用户在 处理模式这种方法使得任务创建代码更加复杂, 可能不适合您的用例。
配置选项
此任务具有以下适用于 iOS 应用的配置选项:
选项名称 | 说明 | 值范围 | 默认值 |
---|---|---|---|
runningMode |
设置任务的运行模式。有三个
模式: IMAGE:单图输入的模式。 VIDEO:视频已解码帧的模式。 LIVE_STREAM:输入流媒体直播模式 例如来自相机的数据。 在此模式下, ImageSegmenterLiveStreamDelegate
必须设置为实现
ImageSegmenterLiveStreamDelegate ,用于接收细分
异步结果。
|
{RunningMode.image, RunningMode.video, RunningMode.liveStream } |
RunningMode.image |
shouldOutputCategoryMask |
如果设置为 True ,则输出将包含细分掩码
表示为 uint8 图片,其中每个像素值表示胜出的类别
值。 |
{True, False } |
False |
shouldOutputConfidenceMasks |
如果设置为 True ,则输出将包含细分掩码
表示为浮点值图片,其中每个浮点值表示
该类别的得分图。 |
{True, False } |
True |
displayNamesLocale |
设置要用于
任务模型的元数据(如果有)。默认值为 en ,
英语。您可以向自定义模型的元数据中添加本地化标签
使用 TensorFlow Lite Metadata Writer API |
语言区域代码 | en |
result_callback |
设置结果监听器以接收细分结果
在图像分割器处于 LIVE_STREAM 模式时异步执行。
仅在跑步模式设为“LIVE_STREAM ”时才能使用 |
不适用 | 不适用 |
当运行模式设置为 LIVE_STREAM
时,图像分割器需要
额外的 imageSegmenterLiveStreamDelegate
配置选项
可让图像分割器异步传送图像分割结果。
代理必须实现
imageSegmenter(_:didFinishSegmentation:timestampInMilliseconds:error:)
方法、
由 Image Segmenter 处理生成的结果,
对每一帧进行分割的过程。
选项名称 | 说明 | 值范围 | 默认值 |
---|---|---|---|
imageSegmenterLiveStreamDelegate |
启用图片分割器以接收执行图片处理的结果
在直播模式下异步细分。实例所属的类
必须实现
imageSegmenter(_:didFinishSegmentation:timestampInMilliseconds:error:)
方法。 |
不适用 | 未设置 |
准备数据
您需要先将输入图片或帧转换为 MPImage
对象,然后才能
传递给图像分割器。MPImage
支持不同类型的 iOS 图片
并且可在任何运行模式下使用它们进行推理。有关
有关 MPImage
的信息,请参阅
MPImage API
根据您的使用情形和应用的运行模式选择 iOS 图片格式
MPImage
接受 UIImage
、CVPixelBuffer
和
CMSampleBuffer
iOS 图片格式。
UIImage
UIImage
格式非常适合以下运行模式:
图片:来自 app bundle、用户图库或文件系统的图片,格式为
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];
本示例使用默认值初始化 MPImage
。
UIImage.Orientation.Up
屏幕方向。您可以使用任何受支持的MPImage
UIImage.Orientation
值。Image Segmenter 不支持镜像方向,例如 .upMirrored
、
.downMirrored
、.leftMirrored
、.rightMirrored
。
有关 UIImage
的详细信息,请参阅 UIImage Apple Developer
文档。
CVPixelBuffer
CVPixelBuffer
格式非常适合生成帧的应用
并使用 iOS CoreImage
处理框架
CVPixelBuffer
格式非常适合以下运行模式:
图片:应用会在经过一些处理后生成
CVPixelBuffer
图片 使用 iOS 的CoreImage
框架发送到 Image Segmenter, 映像运行模式视频:可将视频帧转换为
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 以 CMSampleBuffer
格式异步传送
AVCaptureVideoDataOutput。
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
开发者
文档。
运行任务
要运行图像分割器,请使用特定于指定的 segment()
方法
跑步模式:
- 静态图片:
segment(image:)
- 视频:
segment(videoFrame:timestampInMilliseconds:)
- 直播:
segmentAsync(image:timestampInMilliseconds:)
以下代码示例显示了如何在 Google Cloud 中运行图片分割器 不同的跑步模式:
Swift
映像
let result = try imageSegmenter.segment(image: image)
视频
let result = try imageSegmenter.segment( videoFrame: image, timestampInMilliseconds: timestamp)
直播
try imageSegmenter.segmentAsync( image: image, timestampInMilliseconds: timestamp)
Objective-C
映像
MPPImageSegmenterResult *result = [imageSegmenter segmentImage:image error:nil];
视频
MPPImageSegmenterResult *result = [imageSegmenter segmentVideoFrame:image timestampInMilliseconds:timestamp error:nil];
直播
BOOL success = [imageSegmenter segmentAsyncImage:image timestampInMilliseconds:timestamp error:nil];
图像分割器代码示例展示了以上每种模式的实现
segment(image:)
,
segment(videoFrame:timestampInMilliseconds:)
和
segmentAsync(image:timestampInMilliseconds:)
。
请注意以下几点:
在视频模式或直播模式下投放广告时,您还必须提供 Image Segmenter 任务的输入帧的时间戳。
在图片或视频模式下运行时,图片分割器任务会阻止 当前线程,直到处理完输入图像或帧为止。接收者 避免阻塞当前线程,在后台执行处理 使用 iOS 的会话串 Dispatch 或 NSOperation 框架。
在实时流模式下运行时,Image Segmenter 任务会立即返回 并且不会阻塞当前线程。它会调用
imageSegmenter(_:didFinishSegmentation:timestampInMilliseconds:error:)
方法。通过 Image Segmenter 会在专用序列上异步调用此方法。 调度队列。要在界面上显示结果,请分派 并在处理后将结果发送到主队列中。如果 当图像分割器任务繁忙时,系统会调用segmentAsync
函数 处理其他帧时,图像分割器会忽略新的输入帧。
处理和显示结果
运行推理时,Image Segmenter 任务会返回 ImageSegmenterResult
对象,该对象包含细分任务的结果。该
取决于您在构建新规则时
已配置
任务。
以下图片显示了某个类别的任务输出的可视化图表
值掩码。类别掩码范围为 [0, 255]
,每个像素值
表示模型输出的胜出类别索引。获奖类别
索引在模型可以识别的类别中得分最高。
原始图片和类别遮罩输出。来自 2012 年 Pascal VOC 数据集。
图像分割器示例代码演示了如何显示图像分割器 请参阅代码 示例 了解详情。