Руководство по сегментации изображений для iOS

Задача «Сегментатор изображений» позволяет разделять изображения на области на основе заранее определенных категорий и применять визуальные эффекты, такие как размытие фона. В этих инструкциях показано, как использовать сегментатор изображений с приложениями iOS.

Пример кода, описанный в этой инструкции, доступен на GitHub .

Вы можете увидеть эту задачу в действии, просмотрев веб-демо . Дополнительные сведения о возможностях, моделях и параметрах конфигурации этой задачи см. в разделе Обзор .

Пример кода

Пример кода задач MediaPipe содержит простую реализацию приложения Image Segmenter для iOS.

В примере реализуется сегментатор изображений, который выводит маски категорий. Он использует камеру физического устройства iOS для сегментации изображений в реальном времени с камеры или изображений и видео из галереи устройства.

Вы можете использовать это приложение в качестве отправной точки для своего собственного приложения для iOS или обращаться к нему при изменении существующего приложения. Пример кода Image Segmenter размещен на GitHub .

Загрузите код

Следующие инструкции показывают, как создать локальную копию кода примера с помощью инструмента командной строки git .

Чтобы загрузить пример кода:

  1. Клонируйте репозиторий git, используя следующую команду:

    git clone https://github.com/google-ai-edge/mediapipe-samples/
    
  2. При желании настройте свой экземпляр git на использование разреженной проверки, чтобы у вас были только файлы для примера приложения Image Segmenter:

    cd mediapipe
    git sparse-checkout init --cone
    git sparse-checkout set examples/image_segmentation/ios/
    

После создания локальной версии примера кода вы можете установить библиотеку задач MediaPipe, открыть проект с помощью Xcode и запустить приложение. Инструкции см. в Руководстве по установке для iOS .

Ключевые компоненты

Следующие файлы содержат ключевой код для примера приложения Image Segmenter:

  • ImageSegmenterService.swift : инициализирует сегментатор изображений, обрабатывает выбор модели и выполняет логический вывод на входных данных.
  • CameraViewController.swift : реализует пользовательский интерфейс для режима ввода изображения с камеры в реальном времени и визуализирует результаты.
  • MediaLibraryViewController.swift Реализует пользовательский интерфейс для режима ввода неподвижных изображений и видеофайлов и визуализирует результаты.

Настраивать

В этом разделе описаны ключевые шаги по настройке среды разработки и проектов кода для использования Image Segmenter. Общие сведения о настройке среды разработки для использования задач MediaPipe, включая требования к версии платформы, см. в руководстве по настройке для iOS .

Зависимости

Image Segmenter использует библиотеку MediaPipeTasksVision , которую необходимо установить с помощью CocoaPods. Библиотека совместима с приложениями Swift и Objective-C и не требует дополнительной настройки для конкретного языка.

Инструкции по установке CocoaPods на macOS см. в руководстве по установке CocoaPods . Инструкции о том, как создать Podfile с необходимыми модулями для вашего приложения, см. в разделе Использование CocoaPods .

Добавьте модуль MediaPipeTasksVision в Podfile используя следующий код:

target 'MyImageSegmenterApp' do
  use_frameworks!
  pod 'MediaPipeTasksVision'
end

Если ваше приложение включает в себя цели модульного тестирования, обратитесь к Руководству по настройке для iOS для получения дополнительной информации о настройке вашего Podfile .

Модель

Для задачи сегментации изображений MediaPipe требуется обученная модель, совместимая с этой задачей. Дополнительную информацию о доступных обученных моделях для Image Segmenter смотрите в разделе Models обзора задач.

Выберите и загрузите модель и добавьте ее в каталог проекта с помощью Xcode. Инструкции по добавлению файлов в проект Xcode см. в разделе Управление файлами и папками в проекте Xcode .

Используйте свойство BaseOptions.modelAssetPath , чтобы указать путь к модели в вашем пакете приложений. Пример кода см. в следующем разделе.

Создать задачу

Вы можете создать задачу «Сегментатор изображений», вызвав один из ее инициализаторов. Инициализатор ImageSegmenter(options:) принимает значения для параметров конфигурации.

Если вам не нужен сегментатор изображений, инициализированный с настраиваемыми параметрами конфигурации, вы можете использовать инициализатор ImageSegmenter(modelPath:) для создания сегментатора изображений с параметрами по умолчанию. Дополнительные сведения о параметрах конфигурации см. в разделе Обзор конфигурации .

Задача «Сегментатор изображений» поддерживает три типа входных данных: неподвижные изображения, видеофайлы и прямые видеопотоки. По умолчанию ImageSegmenter(modelPath:) инициализирует задачу для неподвижных изображений. Если вы хотите, чтобы ваша задача была инициализирована для обработки видеофайлов или прямых видеопотоков, используйте ImageSegmenter(options:) , чтобы указать режим работы видео или прямой трансляции. Для режима прямой трансляции также требуется дополнительный параметр конфигурации imageSegmenterLiveStreamDelegate , который позволяет сегментатору изображений асинхронно доставлять результаты сегментации изображения делегату.

Выберите вкладку, соответствующую вашему режиму работы, чтобы узнать, как создать задачу и выполнить вывод.

Быстрый

Изображение

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)
    

Цель-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];
    

Реализация примера кода Image Segmenter позволяет пользователю переключаться между режимами обработки. Такой подход усложняет код создания задачи и может не подойти для вашего варианта использования.

Варианты конфигурации

Эта задача имеет следующие параметры конфигурации для приложений iOS:

Название опции Описание Диапазон значений Значение по умолчанию
runningMode Устанавливает режим выполнения задачи. Есть три режима:

ИЗОБРАЖЕНИЕ: Режим для ввода одного изображения.

ВИДЕО: Режим декодированных кадров видео.

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 английский язык. Вы можете добавить локализованные метки к метаданным пользовательской модели с помощью API записи метаданных TensorFlow Lite. Код региона ru
result_callback Настраивает прослушиватель результатов на асинхронное получение результатов сегментации, когда сегментатор изображений находится в режиме LIVE_STREAM . Может использоваться только в том случае, если для режима работы установлено значение LIVE_STREAM Н/Д Н/Д

Если для режима работы установлено значение LIVE_STREAM , для сегментатора изображений требуется дополнительный параметр конфигурации imageSegmenterLiveStreamDelegate , который позволяет сегментатору изображений доставлять результаты сегментации изображений асинхронно. Делегат должен реализовать метод imageSegmenter(_:didFinishSegmentation:timestampInMilliseconds:error:) , который вызывается Image Segmenter после обработки результатов выполнения сегментации для каждого кадра.

Название опции Описание Диапазон значений Значение по умолчанию
imageSegmenterLiveStreamDelegate Позволяет Image Segmenter получать результаты асинхронной сегментации изображений в режиме прямой трансляции. Класс, экземпляру которого присвоено это свойство, должен реализовать метод imageSegmenter(_:didFinishSegmentation:timestampInMilliseconds:error:) . Непригодный Не установлено

Подготовьте данные

Вам необходимо преобразовать входное изображение или кадр в объект MPImage перед передачей его в сегментатор изображений. MPImage поддерживает различные типы форматов изображений iOS и может использовать их в любом рабочем режиме для вывода. Для получения дополнительной информации о MPImage обратитесь к MPImage API .

Выберите формат изображения iOS в зависимости от вашего варианта использования и режима работы, который требуется вашему приложению. MPImage принимает форматы изображений iOS UIImage , CVPixelBuffer и CMSampleBuffer .

UIImage

Формат UIImage хорошо подходит для следующих режимов работы:

  • Изображения: изображения из пакета приложения, пользовательской галереи или файловой системы, отформатированные как изображения UIImage можно преобразовать в объект MPImage .

  • Видео: используйте AVAssetImageGenerator для извлечения видеокадров в формат CGImage , а затем преобразуйте их в изображения UIImage .

Быстрый

// 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)
    

Цель-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 Documentation .

CVPixelBuffer

Формат CVPixelBuffer хорошо подходит для приложений, генерирующих кадры и использующих для обработки платформу iOS CoreImage .

Формат CVPixelBuffer хорошо подходит для следующих режимов работы:

  • Изображения: приложения, которые генерируют изображения CVPixelBuffer после некоторой обработки с использованием платформы iOS CoreImage , могут быть отправлены в сегментатор изображений в режиме работы изображения.

  • Видео: видеокадры можно конвертировать в формат CVPixelBuffer для обработки, а затем отправлять в сегментатор изображений в режиме видео.

  • прямая трансляция: приложения, использующие камеру iOS для создания кадров, могут быть преобразованы в формат CVPixelBuffer для обработки перед отправкой в ​​сегментатор изображений в режиме прямой трансляции.

Быстрый

// 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)
    

Цель-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 см. в документации разработчика Apple CVPixelBuffer .

CMSampleBuffer

Формат CMSampleBuffer хранит образцы мультимедиа единого типа и хорошо подходит для режима прямой трансляции. Живые кадры с камер iOS асинхронно доставляются в формате CMSampleBuffer с помощью iOS AVCaptureVideoDataOutput .

Быстрый

// 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)
    

Цель-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:)

В следующих примерах кода показаны простые примеры запуска Image Segmenter в различных режимах работы:

Быстрый

Изображение

let result = try imageSegmenter.segment(image: image)
    

Видео

let result = try imageSegmenter.segment(
  videoFrame: image,
  timestampInMilliseconds: timestamp)
    

Прямая трансляция

try imageSegmenter.segmentAsync(
  image: image,
  timestampInMilliseconds: timestamp)
    

Цель-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];
    

В примере кода Image segment(videoFrame:timestampInMilliseconds:) более подробно показаны реализации каждого segmentAsync(image:timestampInMilliseconds:) этих режимов segment(image:)

Обратите внимание на следующее:

  • При работе в режиме видео или режиме прямой трансляции вы также должны предоставить метку времени входного кадра задаче сегментации изображений.

  • При работе в режиме изображения или видео задача «Сегментатор изображений» блокирует текущий поток до тех пор, пока он не завершит обработку входного изображения или кадра. Чтобы избежать блокировки текущего потока, выполните обработку в фоновом потоке с помощью платформ iOS Dispatch или NSOperation .

  • При работе в режиме прямой трансляции задача «Сегментатор изображений» немедленно возвращается и не блокирует текущий поток. Он вызывает метод imageSegmenter(_:didFinishSegmentation:timestampInMilliseconds:error:) с помощью сегментатора изображений после обработки каждого входного кадра. Сегментатор изображений вызывает этот метод асинхронно в выделенной последовательной очереди отправки. Для отображения результатов в пользовательском интерфейсе отправьте результаты в основную очередь после обработки результатов. Если функция segmentAsync вызывается, когда задача сегментации изображений занята обработкой другого кадра, сегментатор изображений игнорирует новый входной кадр.

Обработка и отображение результатов

После выполнения вывода задача Image Segmenter возвращает объект ImageSegmenterResult , который содержит результаты задачи сегментации. Содержимое вывода зависит от типа вывода, который вы установили при настройке задачи.

На следующих изображениях показана визуализация выходных данных задачи для маски значения категории. Диапазон маски категории — [0, 255] , и каждое значение пикселя представляет индекс выигрышной категории выходных данных модели. Индекс выигрышной категории имеет наивысший балл среди категорий, которые может распознать модель.

Вывод исходного изображения и маски категории. Исходное изображение из набора данных Pascal VOC 2012 .

Пример кода сегментатора изображений демонстрирует, как отображать результаты сегментации изображений. Подробности см. в примере кода .