Detectar e rastrear objetos com o Kit de ML no iOS

É possível usar o Kit de ML para detectar e rastrear objetos em frames de vídeo sucessivos.

Quando você transmite uma imagem para o Kit de ML, ele detecta até cinco objetos na imagem junto com a posição de cada objeto na imagem. Ao detectar objetos em streams de vídeo, cada objeto tem um ID exclusivo que pode ser usado para rastrear o objeto de frame a frame. Também é possível ativar objetos brutos que rotula objetos com descrições de categoria amplas.

Faça um teste

Antes de começar

  1. Inclua os seguintes pods do kit de ML no seu Podfile:
    pod 'GoogleMLKit/ObjectDetection', '3.2.0'
    
  2. Depois de instalar ou atualizar os pods do seu projeto, abra o projeto Xcode usando o .xcworkspace: O Kit de ML é compatível com a versão 12.4 ou mais recente do Xcode.

1. Configurar o detector de objetos

Para detectar e rastrear objetos, primeiro crie uma instância de ObjectDetector e, opcionalmente, especificar as configurações de detector que você quer mudar do padrão.

  1. Configure o detector de objetos para seu caso de uso com uma ObjectDetectorOptions. É possível alterar os seguintes configurações:

    Configurações do detector de objetos
    Modo de detecção .stream (padrão) | .singleImage

    No modo de stream (padrão), o detector de objetos é executado com latência, mas pode produzir resultados incompletos (como resultados não especificados caixas delimitadoras ou categorias) nas primeiras invocações de o detector. Além disso, no modo de stream, o detector atribui rastreamento IDs a objetos, que podem ser usados para rastrear objetos em frames. Use esse modo quando quiser rastrear objetos ou quando houver baixa latência é importante, como ao processar streams de vídeo em tempo real tempo de resposta.

    No modo de imagem única, o detector de objetos retorna o resultado depois que a caixa delimitadora do objeto for determinada. Se você também ativar classificação, ela retorna o resultado após a caixa delimitadora e rótulo de categoria estiverem disponíveis. Como consequência, a detecção e a latência é potencialmente maior. Além disso, no modo de imagem única, o rastreamento Os IDs não são atribuídos. Use esse modo se a latência não for essencial e você não deseja lidar com resultados parciais.

    Detectar e rastrear vários objetos false (padrão) | true

    Se deve detectar e rastrear até cinco objetos ou apenas os mais objeto proeminente (padrão).

    Classificar objetos false (padrão) | true

    Define se os objetos detectados serão ou não classificados em categorias abrangentes. Quando ativado, o detector de objetos classifica os objetos na categorias: artigos de moda, alimentos, artigos domésticos, lugares e plantas.

    A API de detecção e rastreamento de objetos é otimizada para essas duas aplicações principais casos:

    • Detecção ao vivo e rastreamento do objeto mais proeminente na câmera visor.
    • Detecção de vários objetos em uma imagem estática.

    Para configurar a API para esses casos de uso:

Swift

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

Objective-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. Receba uma instância de ObjectDetector:

Swift

let objectDetector = ObjectDetector.objectDetector()

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

Objective-C

MLKObjectDetector *objectDetector = [MLKObjectDetector objectDetector];

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

2. Preparar a imagem de entrada

Para detectar e rastrear objetos, siga as etapas abaixo 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 o VisionImage para o processamento de imagem de um dos detectores de objetos. métodos. É possível usar o método process(image:) assíncrono ou o método síncrono results().

Para detectar objetos de forma assíncrona:

Swift

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

Objective-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.
                  }];

Para detectar objetos de maneira síncrona:

Swift

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.

Objective-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. Receber informações sobre objetos detectados

Se a chamada para o processador de imagem for bem-sucedida, ela passará uma lista de Objects para o gerenciador de conclusão ou retorna a lista, dependendo da independentemente de ter chamado o método assíncrono ou síncrono.

Cada Object contém as seguintes propriedades:

frame Um CGRect que indica a posição do objeto no imagem.
trackingID Um número inteiro que identifica o objeto entre imagens, ou "nil" em modo de imagem única.
labels Uma matriz de rótulos que descrevem o objeto retornado pelo detector. A propriedade ficará vazia se a opção do detector shouldEnableClassification é definido como false.

Swift

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

}

Objective-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];
    ...
  }
}

Como melhorar a usabilidade e o desempenho

Para ter a melhor experiência do usuário, siga estas diretrizes no app:

  • A detecção bem-sucedida de objetos depende da complexidade visual do objeto. Em para serem detectados, os objetos com um pequeno número de recursos visuais podem precisar para ocupar uma parte maior da imagem. Você deve fornecer aos usuários orientação sobre capturando entradas que funcionam bem com o tipo de objetos que você quer detectar.
  • Na classificação, para detectar objetos que não se enquadram claramente nas categorias suportadas, implemente tratamento especial para objetos.

Além disso, confira o material design Coleção de padrões para recursos com tecnologia de aprendizado de máquina.

Ao usar o modo de streaming em um aplicativo em tempo real, siga estas diretrizes para: a conseguir as melhores taxas de frames:

  • Não use a detecção de vários objetos no modo de streaming, porque a maioria dos dispositivos não conseguir produzir taxas de quadros adequadas.
  • Desative a classificação se ela não for necessária.
  • Para processar frames de vídeo, use a API síncrona results(in:) do detector. Ligação esse método da AVCaptureVideoDataOutputSampleBufferDelegate captureOutput(_, didOutput:from:) para receber resultados do vídeo fornecido de forma síncrona frame. Manter de AVCaptureVideoDataOutput alwaysDiscardsLateVideoFrames como true para limitar as chamadas ao detector. Se uma nova frame 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 a imagem de entrada, primeiro acesse o resultado do Kit de ML e, em seguida, renderize a imagem e 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. Veja a classe updatePreviewOverlayViewWithLastFrame na amostra do guia de início rápido do Kit de ML.