Detectar poses com o Kit de ML no iOS

O Kit de ML fornece dois SDKs otimizados para detecção de poses.

Nome do SDKPoseDetectionPoseDetectionAccurate
ImplementaçãoOs recursos do detector de base são vinculados estaticamente ao app no tempo de build.Os recursos para um detector preciso são vinculados estaticamente ao app no tempo de build.
Tamanho do appAté 29,6 MBAté 33,2 MB
DesempenhoiPhone X: ~45 QPSiPhone X: ~29 QPS

Faça um teste

Antes de começar

  1. Inclua os seguintes pods do kit de ML no seu Podfile:

    # If you want to use the base implementation:
    pod 'GoogleMLKit/PoseDetection', '3.2.0'
    
    # If you want to use the accurate implementation:
    pod 'GoogleMLKit/PoseDetectionAccurate', '3.2.0'
    
  2. Depois de instalar ou atualizar os pods do seu projeto, abra o projeto do Xcode usando o xcworkspace. O Kit de ML é compatível com o Xcode versão 13.2.1 ou mais recente.

1. Criar uma instância de PoseDetector

Para detectar uma pose em uma imagem, primeiro crie uma instância de PoseDetector e você pode especificar as configurações do detector.

PoseDetector opções

Modo de detecção

O PoseDetector opera em dois modos de detecção. Escolha aquela que corresponde seu caso de uso.

stream (padrão)
O detector de poses primeiro detectará as pessoa proeminente na imagem e, em seguida, executar a detecção de pose. Nos frames subsequentes, a etapa de detecção de pessoa não será realizada, a menos que a pessoa fique obscurecidas ou não são mais detectadas com alta confiança. O detector de poses tentam rastrear a pessoa mais proeminente e voltar a pose em cada a inferência. Isso reduz a latência e suaviza a detecção. Use esse modo quando quiser detectar a pose em um stream de vídeo.
singleImage
O detector de poses detectará uma pessoa e executará a pose detecção de ameaças. A etapa de detecção de pessoa será executada para cada imagem, portanto, a latência ser maior e não há rastreamento de pessoas. Usar este modo ao usar a pose detecção em imagens estáticas ou em que o rastreamento não é desejado.

Especifique as opções do detector de poses:

Swift

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

Por fim, receba uma instância de PoseDetector. Transmita as opções especificadas:

Swift

let poseDetector = PoseDetector.poseDetector(options: options)

Objective-C

MLKPoseDetector *poseDetector =
    [MLKPoseDetector poseDetectorWithOptions:options];

2. Preparar a imagem de entrada

Para detectar poses, faça o seguinte para cada imagem ou frame de vídeo. Se você tiver ativado o modo de stream, precisará criar objetos VisionImage a partir de CMSampleBuffer.

Crie um objeto VisionImage usando um UIImage ou um CMSampleBuffer.

Se você usa um UIImage, siga estas etapas:

  • Crie um objeto VisionImage com o UIImage. Especifique o .orientation correto.

    Swift

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

    Objective-C

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

Se você usa um CMSampleBuffer, siga estas etapas:

  • Especifique a orientação dos dados da imagem contidos no CMSampleBuffer:

    Para saber qual é a orientação da imagem:

    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;
      }
    }
          
  • Crie um objeto VisionImage usando o Objeto e orientação 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. Processar a imagem

Transmita VisionImage para um dos métodos de processamento de imagem do detector de poses. É possível usar o método assíncrono process(image:) ou o síncrono results().

Para detectar objetos de maneira síncrona:

Swift

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.

Para detectar objetos de forma assíncrona:

Swift

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. Receber informações sobre a pose detectada

Se uma pessoa for detectada na imagem, a API de detecção de pose vai transmitir um matriz de objetos Pose para o gerenciador de conclusão ou retorna a matriz, dependendo se você chamou o método assíncrono ou síncrono.

Se a pessoa não estava totalmente dentro da imagem, o modelo atribui as coordenadas de pontos de referência ausentes fora do frame e a baixa InFrameConfidence.

Se nenhuma pessoa for detectada, a matriz vai estar vazia.

Swift

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

Dicas para melhorar o desempenho

A qualidade dos resultados depende da qualidade da imagem de entrada:

  • Para que o Kit de ML detecte a pose com precisão, a pessoa na imagem deve ser representados por dados de pixel suficientes, para obter o melhor desempenho, o assunto deve ter pelo menos 256 x 256 pixels.
  • Se você detectar a pose em um aplicativo em tempo real, também pode considerar as dimensões gerais das imagens de entrada. Imagens menores podem ser processadas mais rápido, portanto, para reduzir a latência, capture imagens em resoluções mais baixas, mas mantenha os requisitos de resolução acima e garantir que o assunto ocupe o máximo possível da imagem.
  • Uma imagem com foco inadequado também pode afetar a precisão. Se você não receber resultados aceitáveis, peça ao usuário para recapturar a imagem.

Se você quiser usar a detecção de pose em um aplicativo em tempo real, siga estas diretrizes para ter as melhores taxas de frames:

  • Usar o SDK do PoseDetection básico e o modo de detecção stream.
  • Capture imagens em uma resolução mais baixa. No entanto, lembre-se também dos requisitos de dimensão de imagem dessa API.
  • Para processar frames de vídeo, use a API síncrona results(in:) do detector. Chame esse método no objeto AVCaptureVideoDataOutputSampleBufferDelegate. Função captureOutput(_, didOutput:from:) para receber os resultados do frame de vídeo de forma síncrona. Mantenha o alwaysDiscardsLateVideoFrames de AVCaptureVideoDataOutput como verdadeiro para limitar as chamadas ao detector. Se um novo quadro de vídeo ficar disponível enquanto o detector estiver em execução, ele será descartado.
  • Se você usar a saída do detector para sobrepor elementos gráficos na imagem de entrada, primeiro acesse o resultado do kit de ML e, em seguida, renderize a imagem e a sobreposição em uma única etapa. Ao fazer isso, você renderiza a superfície de exibição apenas uma vez para cada frame de entrada processado. Consulte a previewOverlayView e MLKDetectionOverlayView no app de exemplo da demonstração.

Próximas etapas