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

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

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

Попробуйте это

Прежде чем начать

  1. Включите в свой подфайл следующие модули ML Kit:
    pod 'GoogleMLKit/ObjectDetection', '15.5.0'
    
  2. После установки или обновления модулей вашего проекта откройте проект Xcode, используя его .xcworkspace . ML Kit поддерживается в Xcode версии 12.4 или новее.

1. Настройте детектор объектов

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

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

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

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

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

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

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

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

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

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

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

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

Быстрый

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

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

Быстрый

let objectDetector = ObjectDetector.objectDetector()

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

Цель-C

MLKObjectDetector *objectDetector = [MLKObjectDetector objectDetector];

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

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

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

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

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

  • Создайте объект VisionImage с помощью UIImage . Обязательно укажите правильную .orientation .

    Быстрый

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

    Цель-C

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

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

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

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

    Быстрый

    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
      }
    }
          

    Цель-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 и ориентацию:

    Быстрый

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

    Цель-C

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

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

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

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

Быстрый

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.
  // ...
}

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

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

Быстрый

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.

Цель-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 s обработчику завершения, либо возвращает список, в зависимости от того, вызвали ли вы асинхронный или синхронный метод.

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

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

Быстрый

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

}

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

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

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

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

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

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

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