Обнаружение поз с помощью ML Kit на iOS

ML Kit предоставляет два оптимизированных SDK для определения поз.

Имя SDK PoseDetection Точное определение позы
Выполнение Активы для базового детектора статически привязываются к вашему приложению во время сборки. Активы для точного детектора статически привязываются к вашему приложению во время сборки.
Размер приложения До 29,6 МБ До 33,2 МБ
Производительность iPhone X: ~45 кадров в секунду iPhone X: ~29 кадров в секунду

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

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

  1. Включите следующие модули ML Kit в свой Podfile:

    # If you want to use the base implementation:
    pod 'GoogleMLKit/PoseDetection', '8.0.0'
    
    # If you want to use the accurate implementation:
    pod 'GoogleMLKit/PoseDetectionAccurate', '8.0.0'
    
  2. После установки или обновления модулей проекта откройте проект Xcode, используя его xcworkspace . ML Kit поддерживается в Xcode версии 13.2.1 и выше.

1. Создайте экземпляр PoseDetector

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

Параметры PoseDetector

Режим обнаружения

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

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

Укажите параметры детектора позы:

Быстрый

// Base pose detector with streaming, when depending on the PoseDetection SDK
let options = PoseDetectorOptions()
options.detectorMode = .stream

// Accurate pose detector on static images, when depending on the
// PoseDetectionAccurate SDK
let options = AccuratePoseDetectorOptions()
options.detectorMode = .singleImage

Objective-C

// Base pose detector with streaming, when depending on the PoseDetection SDK
MLKPoseDetectorOptions *options = [[MLKPoseDetectorOptions alloc] init];
options.detectorMode = MLKPoseDetectorModeStream;

// Accurate pose detector on static images, when depending on the
// PoseDetectionAccurate SDK
MLKAccuratePoseDetectorOptions *options =
    [[MLKAccuratePoseDetectorOptions alloc] init];
options.detectorMode = MLKPoseDetectorModeSingleImage;

Наконец, получите экземпляр PoseDetector и передайте ему указанные вами параметры:

Быстрый

let poseDetector = PoseDetector.poseDetector(options: options)

Objective-C

MLKPoseDetector *poseDetector =
    [MLKPoseDetector poseDetectorWithOptions:options];

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

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

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

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

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

    Быстрый

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

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

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

    Быстрый

    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() .

Для синхронного обнаружения объектов:

Быстрый

var results: [Pose]
do {
  results = try poseDetector.results(in: image)
} catch let error {
  print("Failed to detect pose with error: \(error.localizedDescription).")
  return
}
guard let detectedPoses = results, !detectedPoses.isEmpty else {
  print("Pose detector returned no results.")
  return
}

// Success. Get pose landmarks here.

Objective-C

NSError *error;
NSArray *poses = [poseDetector resultsInImage:image error:&error];
if (error != nil) {
  // Error.
  return;
}
if (poses.count == 0) {
  // No pose detected.
  return;
}

// Success. Get pose landmarks here.

Для асинхронного обнаружения объектов:

Быстрый

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

  // Success. Get pose landmarks here.
}

Objective-C

[poseDetector processImage:image
                completion:^(NSArray * _Nullable poses,
                             NSError * _Nullable error) {
                    if (error != nil) {
                      // Error.
                      return;
                    }
                    if (poses.count == 0) {
                      // No pose detected.
                      return;
                    }

                    // Success. Get pose landmarks here.
                  }];

4. Получите информацию об обнаруженной позе.

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

Если человек не полностью попал в кадр, модель присваивает недостающим ориентирам координаты за пределами кадра и присваивает им низкие значения InFrameConfidence.

Если человек не обнаружен, массив пуст.

Быстрый

for pose in detectedPoses {
  let leftAnkleLandmark = pose.landmark(ofType: .leftAnkle)
  if leftAnkleLandmark.inFrameLikelihood > 0.5 {
    let position = leftAnkleLandmark.position
  }
}

Objective-C

for (MLKPose *pose in detectedPoses) {
  MLKPoseLandmark *leftAnkleLandmark =
      [pose landmarkOfType:MLKPoseLandmarkTypeLeftAnkle];
  if (leftAnkleLandmark.inFrameLikelihood > 0.5) {
    MLKVision3DPoint *position = leftAnkleLandmark.position;
  }
}

Советы по повышению производительности

Качество ваших результатов зависит от качества входного изображения:

  • Чтобы ML Kit мог точно определить позу, человек на изображении должен быть представлен достаточным количеством пиксельных данных; для наилучшей производительности размер объекта должен быть не менее 256x256 пикселей.
  • Если вы определяете позу в приложении реального времени, вам также стоит учитывать общие размеры входных изображений. Изображения меньшего размера обрабатываются быстрее, поэтому для уменьшения задержки снимайте с более низким разрешением, но учитывайте вышеуказанные требования к разрешению и следите за тем, чтобы объект занимал как можно большую часть изображения.
  • Плохая фокусировка изображения также может повлиять на точность. Если результаты неудовлетворительны, попросите пользователя переснять изображение.

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

  • Используйте базовый PoseDetection SDK и режим stream обнаружения.
  • Рассмотрите возможность захвата изображений в более низком разрешении. Однако учитывайте требования API к размерам изображений.
  • Для обработки видеокадров используйте синхронный API results(in:) детектора. Вызовите этот метод из функции captureOutput(_, didOutput:from:) класса AVCaptureVideoDataOutputSampleBufferDelegate для синхронного получения результатов из заданного видеокадра. Для ограничения вызовов детектора установите значение alwaysDiscardsLateVideoFrames класса AVCaptureVideoDataOutput равным true. Если новый видеокадр станет доступен во время работы детектора, он будет отброшен.
  • Если вы используете выходные данные детектора для наложения графики на входное изображение, сначала получите результат из ML Kit, а затем визуализируйте изображение и наложение за один шаг. Таким образом, визуализация на поверхности дисплея выполняется только один раз для каждого обработанного входного кадра. См. примеры классов previewOverlayView и MLKDetectionOverlayView в демонстрационном примере приложения.

Следующие шаги