Обнаружение и отслеживание объектов с помощью ML Kit в iOS

С помощью ML Kit можно обнаруживать и отслеживать объекты в последовательных кадрах видео.

Когда вы передаете изображение в ML Kit, он обнаруживает на изображении до пяти объектов, а также положение каждого объекта на изображении. При обнаружении объектов в видеопотоках каждому объекту присваивается уникальный идентификатор, который можно использовать для отслеживания объекта от кадра к кадру. Вы также можете включить приблизительную классификацию объектов, которая помечает объекты описаниями широких категорий.

Попробовать

Подготовка

  1. Добавьте в Podfile следующие контейнеры ML Kit:
    pod 'GoogleMLKit/ObjectDetection', '8.0.0'
    
  2. После установки или обновления Pods откройте проект Xcode, используя файл .xcworkspace. ML Kit поддерживается в Xcode версии 12.4 и более поздних.

1. Как настроить детектор объектов

Чтобы обнаруживать объекты и отслеживать их перемещение, сначала создайте экземпляр класса ObjectDetector и при необходимости укажите настройки детектора, которые вы хотите изменить.

  1. Настройте детектор объектов для своего варианта использования с помощью объекта ObjectDetectorOptions. Вы можете изменить следующие настройки:

    Настройки детектора объектов
    Режим обнаружения .stream (по умолчанию) | .singleImage

    В режиме потока (по умолчанию) детектор объектов работает с очень низкой задержкой, но при первых нескольких вызовах может выдавать неполные результаты (например, неопределенные ограничительные рамки или категории). Кроме того, в режиме потоковой передачи детектор присваивает объектам идентификаторы отслеживания, которые можно использовать для отслеживания объектов на разных кадрах. Используйте этот режим, если вам нужно отслеживать объекты или если важна низкая задержка, например при обработке видеопотоков в реальном времени.

    В режиме одного изображения детектор объектов возвращает результат после определения ограничительной рамки объекта. Если вы также включите классификацию, результат будет возвращен после того, как будут доступны граничная рамка и ярлык категории. В результате задержка обнаружения может быть выше. Кроме того, в режиме одного изображения идентификаторы отслеживания не назначаются. Используйте этот режим, если задержка не критична и вы не хотите иметь дело с частичными результатами.

    Обнаружение и отслеживание нескольких объектов false (по умолчанию) | true

    Нужно ли обнаруживать и отслеживать до пяти объектов или только самый заметный объект (по умолчанию).

    Классифицировать объекты false (по умолчанию) | true

    Нужно ли классифицировать обнаруженные объекты по категориям. Если эта функция включена, детектор объектов классифицирует объекты по следующим категориям: одежда, еда, товары для дома, места и растения.

    API обнаружения и отслеживания объектов оптимизирован для двух основных вариантов использования:

    • Обнаружение и отслеживание в реальном времени наиболее заметного объекта в видоискателе камеры.
    • Обнаружение нескольких объектов на статичном изображении.

    Чтобы настроить API для этих вариантов использования:

Swift

// Live detection and tracking
let options = ObjectDetectorOptions()
options.shouldEnableClassification = true

// Multiple object detection in static images
let options = ObjectDetectorOptions()
options.detectorMode = .singleImage
options.shouldEnableMultipleObjects = true
options.shouldEnableClassification = true

Objective-C

// Live detection and tracking
MLKObjectDetectorOptions *options = [[MLKObjectDetectorOptions alloc] init];
options.shouldEnableClassification = YES;

// Multiple object detection in static images
MLKObjectDetectorOptions *options = [[MLKOptions alloc] init];
options.detectorMode = MLKObjectDetectorModeSingleImage;
options.shouldEnableMultipleObjects = YES;
options.shouldEnableClassification = YES;
  1. Получите экземпляр ObjectDetector:

Swift

let objectDetector = ObjectDetector.objectDetector()

// Or, to change the default settings:
let objectDetector = ObjectDetector.objectDetector(options: options)

Objective-C

MLKObjectDetector *objectDetector = [MLKObjectDetector objectDetector];

// Or, to change the default settings:
MLKObjectDetector *objectDetector = [MLKObjectDetector objectDetectorWithOptions:options];

2. Как подготовить входное изображение

Чтобы обнаружить и отслеживать объекты, выполните следующие действия для каждого изображения или кадра видео. Если вы включили режим потока, то должны создать объекты VisionImage из объектов CMSampleBuffer.

Создайте объект VisionImage, используя UIImage или CMSampleBuffer.

Если вы используете UIImage, выполните следующие действия:

  • Создайте объект VisionImage с UIImage. Убедитесь, что вы указали правильное значение параметра .orientation.

    Swift

    let image = VisionImage(image: UIImage)
    visionImage.orientation = image.imageOrientation

    Objective-C

    MLKVisionImage *visionImage = [[MLKVisionImage alloc] initWithImage:image];
    visionImage.orientation = image.imageOrientation;

Если вы используете CMSampleBuffer, выполните следующие действия:

  • Укажите ориентацию изображения, содержащегося в CMSampleBuffer.

    Чтобы получить ориентацию изображения:

    Swift

    func imageOrientation(
      deviceOrientation: UIDeviceOrientation,
      cameraPosition: AVCaptureDevice.Position
    ) -> UIImage.Orientation {
      switch deviceOrientation {
      case .portrait:
        return cameraPosition == .front ? .leftMirrored : .right
      case .landscapeLeft:
        return cameraPosition == .front ? .downMirrored : .up
      case .portraitUpsideDown:
        return cameraPosition == .front ? .rightMirrored : .left
      case .landscapeRight:
        return cameraPosition == .front ? .upMirrored : .down
      case .faceDown, .faceUp, .unknown:
        return .up
      }
    }
          

    Objective-C

    - (UIImageOrientation)
      imageOrientationFromDeviceOrientation:(UIDeviceOrientation)deviceOrientation
                             cameraPosition:(AVCaptureDevicePosition)cameraPosition {
      switch (deviceOrientation) {
        case UIDeviceOrientationPortrait:
          return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationLeftMirrored
                                                                : UIImageOrientationRight;
    
        case UIDeviceOrientationLandscapeLeft:
          return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationDownMirrored
                                                                : UIImageOrientationUp;
        case UIDeviceOrientationPortraitUpsideDown:
          return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationRightMirrored
                                                                : UIImageOrientationLeft;
        case UIDeviceOrientationLandscapeRight:
          return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationUpMirrored
                                                                : UIImageOrientationDown;
        case UIDeviceOrientationUnknown:
        case UIDeviceOrientationFaceUp:
        case UIDeviceOrientationFaceDown:
          return UIImageOrientationUp;
      }
    }
          
  • Создайте объект VisionImage, используя объект CMSampleBuffer и ориентацию:

    Swift

    let image = VisionImage(buffer: sampleBuffer)
    image.orientation = imageOrientation(
      deviceOrientation: UIDevice.current.orientation,
      cameraPosition: cameraPosition)

    Objective-C

     MLKVisionImage *image = [[MLKVisionImage alloc] initWithBuffer:sampleBuffer];
     image.orientation =
       [self imageOrientationFromDeviceOrientation:UIDevice.currentDevice.orientation
                                    cameraPosition:cameraPosition];

3. Обработка изображения

Передайте VisionImage одному из методов обработки изображений детектора объектов. Вы можете использовать асинхронный метод process(image:) или синхронный метод results().

Чтобы обнаружить объекты асинхронно:

Swift

objectDetector.process(image) { objects, error in
  guard error == nil else {
    // Error.
    return
  }
  guard !objects.isEmpty else {
    // No objects detected.
    return
  }

  // Success. Get object info here.
  // ...
}

Objective-C

[objectDetector processImage:image
                  completion:^(NSArray * _Nullable objects,
                               NSError * _Nullable error) {
                    if (error == nil) {
                      return;
                    }
                    if (objects.count == 0) {
                      // No objects detected.
                      return;
                    }

                    // Success. Get object info here.
                  }];

Чтобы распознавать объекты синхронно:

Swift

var objects: [Object]
do {
  objects = try objectDetector.results(in: image)
} catch let error {
  print("Failed to detect object with error: \(error.localizedDescription).")
  return
}
guard !objects.isEmpty else {
  print("Object detector returned no results.")
  return
}

// Success. Get object info here.

Objective-C

NSError *error;
NSArray *objects = [objectDetector resultsInImage:image error:&error];
if (error == nil) {
  return;
}
if (objects.count == 0) {
  // No objects detected.
  return;
}

// Success. Get object info here.

4. Как получать информацию об обнаруженных объектах

Если вызов обработчика изображений выполнен успешно, он передает список объектов Object обработчику завершения или возвращает этот список (в зависимости от того, какой метод был вызван – асинхронный или синхронный).

Каждый объект Object содержит следующие свойства:

frame Элемент CGRect, указывающий положение объекта на изображении.
trackingID Целое число, которое идентифицирует объект на разных изображениях, или значение nil в режиме одного изображения.
labels Массив ярлыков, описывающих объект, возвращенный детектором. Если для параметра детектора shouldEnableClassification задано значение false, свойство будет пустым.

Swift

// objects contains one item if multiple object detection wasn't enabled.
for object in objects {
  let frame = object.frame
  let trackingID = object.trackingID

  // If classification was enabled:
  let description = object.labels.enumerated().map { (index, label) in
    "Label \(index): \(label.text), \(label.confidence)"
    }.joined(separator:"\n")

}

Objective-C

// The list of detected objects contains one item if multiple
// object detection wasn't enabled.
for (MLKObject *object in objects) {
  CGRect frame = object.frame;
  NSNumber *trackingID = object.trackingID;
  for (MLKObjectLabel *label in object.labels) {
    NSString *labelString = [NSString stringWithFormat: @"%@, %f, %lu",
      label.text, label.confidence, (unsigned long)label.index];
    ...
  }
}

Улучшение удобства использования и производительности

Чтобы обеспечить удобство пользователей, следуйте этим рекомендациям:

  • Успешное обнаружение объектов зависит от их визуальной сложности. Чтобы объекты с небольшим количеством визуальных признаков были обнаружены, они должны занимать большую часть изображения. Пользователям нужно предоставить инструкции по съемке объектов, которые вы хотите распознавать.
  • Если вы используете классификацию и хотите обнаруживать объекты, которые не относятся к поддерживаемым категориям, реализуйте специальную обработку неизвестных объектов.

Также ознакомьтесь с коллекцией шаблонов для функций на основе машинного обучения в Material Design.

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

  • Не используйте обнаружение нескольких объектов в режиме потоковой передачи, так как большинство устройств не смогут обеспечить адекватную частоту кадров.
  • Если классификация вам не нужна, отключите ее.
  • Для обработки кадров видео используйте синхронный API детектора results(in:). Вызовите этот метод из функции captureOutput(_, didOutput:from:) объекта AVCaptureVideoDataOutputSampleBufferDelegate, чтобы синхронно получить результаты для заданного кадра видео. Установите для параметра AVCaptureVideoDataOutput значение alwaysDiscardsLateVideoFrames, чтобы ограничить количество вызовов детектора.true Если во время работы детектора станет доступен новый кадр видео, он будет отброшен.
  • Если вы используете результаты работы детектора для наложения графики на входное изображение, сначала получите результат от ML Kit, а затем отрисуйте изображение и наложите графику за один шаг. В этом случае отрисовка на поверхности экрана выполняется только один раз для каждого обработанного входного кадра. Пример можно найти в разделе updatePreviewOverlayViewWithLastFrame в руководстве по быстрому началу работы с ML Kit.