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

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

Название SDK Обнаружение позы Точное определение позы
Выполнение Ресурсы для базового детектора статически связываются с вашим приложением во время сборки. Ресурсы для точного обнаружения статически связываются с вашим приложением во время сборки.
Размер приложения До 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 пикселей.
  • Если вы определяете позу в приложении реального времени, вам также следует учитывать общие размеры входных изображений. Изображения меньшего размера обрабатываются быстрее, поэтому для уменьшения задержки захватывайте изображения с более низким разрешением, но помните о вышеуказанных требованиях к разрешению и убедитесь, что объект занимает как можно большую часть изображения.
  • Плохая фокусировка изображения также может повлиять на точность. Если вы не получаете приемлемых результатов, попросите пользователя сделать повторный снимок.

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

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

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