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

Задача MediaPipe Image Embedder позволяет преобразовывать данные изображения в числовое представление для выполнения задач обработки изображений, связанных с машинным обучением, таких как сравнение сходства двух изображений.

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

Пример кода

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

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

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

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

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

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

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

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

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

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

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

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

Настраивать

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

Зависимости

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

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

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

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

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

Модель

Для задачи MediaPipe Image Embedder требуется обученная модель, совместимая с этой задачей. Дополнительную информацию о доступных обученных моделях для Image Embedder смотрите в разделе «Модели» .

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

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

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

Вы можете создать задачу Image Embedder, вызвав один из ее инициализаторов. Инициализатор ImageEmbedder(options:) принимает значения параметров конфигурации.

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

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

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

Быстрый

Изображение

import MediaPipeTasksVision

let modelPath = Bundle.main.path(
  forResource: "model",
  ofType: "tflite")

let options = ImageEmbedderOptions()
options.baseOptions.modelAssetPath = modelPath
options.quantize = true
options.l2Normalize = true

let imageEmbedder = try ImageEmbedder(options: options)
    

Видео

import MediaPipeTasksVision

let modelPath = Bundle.main.path(
  forResource: "model",
  ofType: "tflite")

let options = ImageEmbedderOptions()
options.baseOptions.modelAssetPath = modelPath
options.runningMode = .video
options.quantize = true
options.l2Normalize = true

let imageEmbedder = try ImageEmbedder(options: options)
    

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

import MediaPipeTasksVision

// Class that conforms to the `ImageEmbedderLiveStreamDelegate` protocol and
// implements the method that the image embedder calls once it finishes
// embedding each input frame.
class ImageEmbedderResultProcessor: NSObject, ImageEmbedderLiveStreamDelegate {

  func imageEmbedder(
    _ imageEmbedder: ImageEmbedder,
    didFinishEmbedding result: ImageEmbedderResult?,
    timestampInMilliseconds: Int,
    error: Error?) {

    // Process the image embedder result or errors here.

  }
}

let modelPath = Bundle.main.path(
  forResource: "model",
  ofType: "tflite")

let options = ImageEmbedderOptions()
options.baseOptions.modelAssetPath = modelPath
options.runningMode = .liveStream
options.quantize = true
options.l2Normalize = true

// Assign an object of the class to the `imageEmbedderLiveStreamDelegate`
// property.
let processor = ImageEmbedderResultProcessor()
options.imageEmbedderLiveStreamDelegate = processor

let imageEmbedder = try ImageEmbedder(options: options)
    

Цель-C

Изображение

@import MediaPipeTasksVision;

NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"model"
                                                      ofType:@"tflite"];

MPPImageEmbedderOptions *options = [[MPPImageEmbedderOptions alloc] init];
options.baseOptions.modelAssetPath = modelPath;
options.runningMode = MPPRunningModeImage;
options.quantize = YES;
options.l2Normalize = YES;

MPPImageEmbedder *imageEmbedder =
  [[MPPImageEmbedder alloc] initWithOptions:options error:nil];
    

Видео

@import MediaPipeTasksVision;

NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"model"
                                                      ofType:@"tflite"];

MPPImageEmbedderOptions *options = [[MPPImageEmbedderOptions alloc] init];
options.baseOptions.modelAssetPath = modelPath;
options.runningMode = MPPRunningModeVideo;
options.quantize = YES;
options.l2Normalize = YES;

MPPImageEmbedder *imageEmbedder =
  [[MPPImageEmbedder alloc] initWithOptions:options error:nil];
    

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

@import MediaPipeTasksVision;

// Class that conforms to the `MPPImageEmbedderLiveStreamDelegate` protocol
// and implements the method that the image embedder calls once it finishes
// embedding each input frame.
@interface APPImageEmbedderResultProcessor : NSObject 

@end

@implementation APPImageEmbedderResultProcessor

-   (void)imageEmbedder:(MPPImageEmbedder *)imageEmbedder
    didFinishEmbeddingWithResult:(MPPImageEmbedderResult *)imageEmbedderResult
         timestampInMilliseconds:(NSInteger)timestampInMilliseconds
                           error:(NSError *)error {

    // Process the image embedder result or errors here.

}

@end

NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"model"
                                                      ofType:@"tflite"];

MPPImageEmbedderOptions *options = [[MPPImageEmbedderOptions alloc] init];
options.baseOptions.modelAssetPath = modelPath;
options.runningMode = MPPRunningModeLiveStream;
options.quantize = YES;
options.l2Normalize = YES;

// Assign an object of the class to the `imageEmbedderLiveStreamDelegate`
// property.
APPImageEmbedderResultProcessor *processor =
  [APPImageEmbedderResultProcessor new];
options.imageEmbedderLiveStreamDelegate = processor;

MPPImageEmbedder *imageEmbedder =
  [[MPPImageEmbedder alloc] initWithOptions:options error:nil];
    

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

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

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

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

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

LIVE_STREAM: режим прямой трансляции входных данных, например с камеры. В этом режиме imageEmbedderLiveStreamDelegate необходимо задать экземпляр класса, который реализует ImageEmbedderLiveStreamDelegate , чтобы асинхронно получать результаты внедрения кадров изображения.
{RunningMode.image, RunningMode.video, RunningMode.liveStream} {RunningMode.image}
l2Normalize Нормализовать ли возвращенный вектор признаков по норме L2. Используйте эту опцию, только если модель еще не содержит встроенный L2_NORMALIZATION TFLite Op. В большинстве случаев это уже так, и нормализация L2, таким образом, достигается посредством вывода TFLite без необходимости использования этой опции. Бул ЛОЖЬ
quantize Следует ли квантовать возвращенное внедрение в байты посредством скалярного квантования. Неявно предполагается, что вложения имеют единичную норму, и поэтому любое измерение гарантированно имеет значение в [-1.0, 1.0]. Если это не так, используйте опцию l2Normalize. Бул ЛОЖЬ

Если в качестве рабочего режима установлена ​​прямая трансляция, для Image Embedder требуется дополнительный параметр конфигурации imageEmbedderLiveStreamDelegate , который позволяет Image Embedder асинхронно доставлять результаты внедрения изображений. Делегат должен реализовать метод imageEmbedder(_:didFinishEmbedding:timestampInMilliseconds:error:) , который Image Embedder вызывает после обработки результатов внедрения каждого кадра входного изображения.

Название опции Описание Диапазон значений Значение по умолчанию
imageEmbedderLiveStreamDelegate Позволяет Image Embedder асинхронно получать результаты внедрения изображений в режиме прямой трансляции. Класс, экземпляру которого присвоено это свойство, должен реализовать метод imageEmbedder(_:didFinishEmbedding: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 Embedder не поддерживает зеркальные ориентации, такие как .upMirrored , .downMirrored , .leftMirrored , .rightMirrored .

Для получения дополнительной информации о UIImage обратитесь к документации UIImage Apple Developer Documentation .

CVPixelBuffer

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

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

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

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

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

Быстрый

// 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 для разработчиков .

Запустить задачу

Чтобы запустить Image Embedder, используйте метод embed() соответствующий назначенному режиму работы:

  • Неподвижное изображение: embed(image:)
  • Видео: embed(videoFrame:timestampInMilliseconds:)
  • Прямая трансляция: embedAsync(image:timestampInMilliseconds:)

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

Быстрый

Изображение

let result = try imageEmbedder.embed(image: image)
    

Видео

let result = try imageEmbedder.embed(
  videoFrame: image,
  timestampInMilliseconds: timestamp)
    

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

try imageEmbedder.embedAsync(
  image: image,
  timestampInMilliseconds: timestamp)
    

Цель-C

Изображение

MPPImageEmbedderResult *result =
  [imageEmbedder embedImage:image error:nil];
    

Видео

MPPImageEmbedderResult *result =
  [imageEmbedder embedVideoFrame:image
           timestampInMilliseconds:timestamp
                             error:nil];
    

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

BOOL success =
  [imageEmbedder embedAsyncImage:image
           timestampInMilliseconds:timestamp
                             error:nil];
    

В примере кода Image Embedder более подробно показаны реализации каждого из этих режимов embed(image:) , embed(videoFrame:timestampInMilliseconds:) и embedAsync(image:timestampInMilliseconds:) . Пример кода позволяет пользователю переключаться между режимами обработки, которые могут не потребоваться для вашего варианта использования.

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

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

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

  • При работе в режиме прямой трансляции задача Image Embedder немедленно возвращается и не блокирует текущий поток. Он вызывает метод imageEmbedder(_:didFinishEmbedding:timestampInMilliseconds:error:) с результатами после внедрения каждого входного кадра. Image Embedder вызывает этот метод асинхронно в выделенной последовательной очереди отправки. Для отображения результатов в пользовательском интерфейсе отправьте результаты в основную очередь после обработки результатов. Если функция embedAsync вызывается, когда задача Image Embedder занята обработкой другого кадра, Image Embedder игнорирует новый входной кадр.

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

После выполнения вывода Image Embedder возвращает объект ImageEmbedderResult , который содержит список внедрений (с плавающей запятой или скалярно-квантованных) для входного изображения.

Ниже показан пример выходных данных этой задачи:

ImageEmbedderResult:
  Embedding #0 (sole embedding head):
    float_embedding: {0.0, 0.0, ..., 0.0, 1.0, 0.0, 0.0, 2.0}
    head_index: 0

Этот результат был получен путем встраивания следующего изображения:

Вы можете сравнить сходство двух вложений, используя функцию ImageEmbedder.cosineSimilarity .

Быстрый

let similarity = try ImageEmbedder.cosineSimilarity(
  embedding1: result.embeddingResult.embeddings[0],
  embedding2: otherResult.embeddingResult.embeddings[0])
    

Цель-C

NSNumber *similarity = [MPPImageEmbedder
      cosineSimilarityBetweenEmbedding1:result.embeddingResult.embeddings[0]
                          andEmbedding2:otherResult.embeddingResult.embeddings[0]
                                  error:nil];