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

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

Имя SDK PoseDetection PoseDetectionAccurate
Выполнение Активы для базового детектора статически привязываются к вашему приложению во время сборки. Активы для точного детектора статически привязываются к вашему приложению во время сборки.
Размер приложения До 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 s.

Создайте объект 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 в демонстрационном примере приложения для примера.

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