É possível usar o Kit de ML para detectar e rastrear objetos em frames de vídeo.
Quando você transmite imagens do Kit de ML, ele retorna, para cada imagem, uma lista de até cinco objetos detectados e a posição deles na imagem. Cada objeto que você detecta em streams de vídeo tem um ID que pode ser rastreado nas imagens. É possível também, como opção, ativar a classificação abrangente de objetos, que marca objetos com descrições de categorias amplas.
Antes de começar
- Se você ainda não adicionou o Firebase ao seu app, siga as etapas no guia de iniciação.
- Inclua as bibliotecas do Kit de ML no seu Podfile:
pod 'Firebase/MLVision', '6.25.0' pod 'Firebase/MLVisionObjectDetection', '6.25.0'
Depois de instalar ou atualizar os pods do projeto, abra o projeto do Xcode usando o.xcworkspace
. - Importe o Firebase para seu app:
Swift
import Firebase
Objective-C
@import Firebase;
1. Configurar o detector de objetos
Para começar a detectar e rastrear objetos, primeiro crie uma instância de
VisionObjectDetector
, especificando opcionalmente as configurações do detector que você quer
alterar do padrão.
Configure o detector de objetos para seu caso de uso com um objeto
VisionObjectDetectorOptions
. É possível alterar as seguintes configurações:Configurações do detector de objetos Modo de detecção .stream
(padrão) |.singleImage
No modo de streaming (padrão), o detector de objetos é executado com baixa latência, mas pode produzir resultados incompletos, como caixas delimitadoras ou categoria não especificadas, nas primeiras chamadas do detector. Além disso, no modo de streaming, o detector atribui IDs de rastreamento a objetos, que podem ser usados para rastrear objetos em frames. Use esse modo quando quiser rastrear objetos ou quando a baixa latência for importante, como ao processar streams de vídeo em tempo real.
No modo de imagem única, o detector de objetos aguarda até que a caixa delimitadora e a categoria (se você tiver ativado a classificação) de um objeto detectado estejam disponíveis antes de retornar um resultado. Como resultado, a latência de detecção é potencialmente maior. Além disso, no modo de imagem única, os IDs de acompanhamento não são atribuídos. Use esse modo se a latência não for essencial e você não quiser lidar com resultados parciais.
Detectar e rastrear vários objetos false
(padrão) |true
Se for preciso detectar e rastrear até cinco objetos ou apenas o objeto mais proeminente (padrão).
Classificar objetos false
(padrão) |true
Se for preciso ou não classificar os objetos detectados em categorias abrangentes. Quando ativado, o detector de objetos os classifica nas seguintes categorias: artigos de moda, alimentos, artigos domésticos, locais, plantas e desconhecido.
A API de detecção e rastreamento de objetos é otimizada para os dois casos de uso principais a seguir:
- Detecção ao vivo e rastreamento do objeto mais proeminente no visor da câmera
- 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 = VisionObjectDetectorOptions() options.detectorMode = .stream options.shouldEnableMultipleObjects = false options.shouldEnableClassification = true // Optional // Multiple object detection in static images let options = VisionObjectDetectorOptions() options.detectorMode = .singleImage options.shouldEnableMultipleObjects = true options.shouldEnableClassification = true // Optional
Objective-C
// Live detection and tracking FIRVisionObjectDetectorOptions *options = [[FIRVisionObjectDetectorOptions alloc] init]; options.detectorMode = FIRVisionObjectDetectorModeStream; options.shouldEnableMultipleObjects = NO; options.shouldEnableClassification = YES; // Optional // Multiple object detection in static images FIRVisionObjectDetectorOptions *options = [[FIRVisionObjectDetectorOptions alloc] init]; options.detectorMode = FIRVisionObjectDetectorModeSingleImage; options.shouldEnableMultipleObjects = YES; options.shouldEnableClassification = YES; // Optional
Receba uma instância de
FirebaseVisionObjectDetector
:Swift
let objectDetector = Vision.vision().objectDetector() // Or, to change the default settings: let objectDetector = Vision.vision().objectDetector(options: options)
Objective-C
FIRVisionObjectDetector *objectDetector = [[FIRVision vision] objectDetector]; // Or, to change the default settings: FIRVisionObjectDetector *objectDetector = [[FIRVision vision] objectDetectorWithOptions:options];
2. Executar o detector de objetos
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
CMSampleBufferRef
.
Crie um objeto
VisionImage
usando umUIImage
ou umCMSampleBufferRef
.Para usar um
UIImage
:- Se necessário, gire a imagem para que a propriedade
imageOrientation
seja.up
. - Crie um objeto
VisionImage
usando aUIImage
com a rotação correta. Não especifique metadados de rotação: o valor padrão,.topLeft
, precisa ser usado.Swift
let image = VisionImage(image: uiImage)
Objective-C
FIRVisionImage *image = [[FIRVisionImage alloc] initWithImage:uiImage];
Para usar um
CMSampleBufferRef
:-
Crie um objeto
VisionImageMetadata
que especifique a orientação dos dados da imagem contidos no bufferCMSampleBufferRef
.Para ver a orientação da imagem:
Swift
func imageOrientation( deviceOrientation: UIDeviceOrientation, cameraPosition: AVCaptureDevice.Position ) -> VisionDetectorImageOrientation { switch deviceOrientation { case .portrait: return cameraPosition == .front ? .leftTop : .rightTop case .landscapeLeft: return cameraPosition == .front ? .bottomLeft : .topLeft case .portraitUpsideDown: return cameraPosition == .front ? .rightBottom : .leftBottom case .landscapeRight: return cameraPosition == .front ? .topRight : .bottomRight case .faceDown, .faceUp, .unknown: return .leftTop } }
Objective-C
- (FIRVisionDetectorImageOrientation) imageOrientationFromDeviceOrientation:(UIDeviceOrientation)deviceOrientation cameraPosition:(AVCaptureDevicePosition)cameraPosition { switch (deviceOrientation) { case UIDeviceOrientationPortrait: if (cameraPosition == AVCaptureDevicePositionFront) { return FIRVisionDetectorImageOrientationLeftTop; } else { return FIRVisionDetectorImageOrientationRightTop; } case UIDeviceOrientationLandscapeLeft: if (cameraPosition == AVCaptureDevicePositionFront) { return FIRVisionDetectorImageOrientationBottomLeft; } else { return FIRVisionDetectorImageOrientationTopLeft; } case UIDeviceOrientationPortraitUpsideDown: if (cameraPosition == AVCaptureDevicePositionFront) { return FIRVisionDetectorImageOrientationRightBottom; } else { return FIRVisionDetectorImageOrientationLeftBottom; } case UIDeviceOrientationLandscapeRight: if (cameraPosition == AVCaptureDevicePositionFront) { return FIRVisionDetectorImageOrientationTopRight; } else { return FIRVisionDetectorImageOrientationBottomRight; } default: return FIRVisionDetectorImageOrientationTopLeft; } }
Em seguida, crie o objeto de metadados:
Swift
let cameraPosition = AVCaptureDevice.Position.back // Set to the capture device you used. let metadata = VisionImageMetadata() metadata.orientation = imageOrientation( deviceOrientation: UIDevice.current.orientation, cameraPosition: cameraPosition )
Objective-C
FIRVisionImageMetadata *metadata = [[FIRVisionImageMetadata alloc] init]; AVCaptureDevicePosition cameraPosition = AVCaptureDevicePositionBack; // Set to the capture device you used. metadata.orientation = [self imageOrientationFromDeviceOrientation:UIDevice.currentDevice.orientation cameraPosition:cameraPosition];
- Crie um objeto
VisionImage
usando o objetoCMSampleBufferRef
e os metadados de rotação:Swift
let image = VisionImage(buffer: sampleBuffer) image.metadata = metadata
Objective-C
FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer]; image.metadata = metadata;
- Se necessário, gire a imagem para que a propriedade
Passe o
VisionImage
para um dos métodos de processamento de imagem do detector de objetos. É possível usar o métodoprocess(image:)
assíncrono ou o métodoresults()
síncrono.Para detectar objetos de modo assíncrono:
Swift
objectDetector.process(image) { detectedObjects, error in guard error == nil else { // Error. return } guard let detectedObjects = detectedObjects, !detectedObjects.isEmpty else { // No objects detected. return } // Success. Get object info here. // ... }
Objective-C
[objectDetector processImage:image completion:^(NSArray<FIRVisionObject *> * _Nullable objects, NSError * _Nullable error) { if (error == nil) { return; } if (objects == nil | objects.count == 0) { // No objects detected. return; } // Success. Get object info here. // ... }];
Para detectar objetos de modo síncrono:
Swift
var results: [VisionObject]? = nil do { results = try objectDetector.results(in: image) } catch let error { print("Failed to detect object with error: \(error.localizedDescription).") return } guard let detectedObjects = results, !detectedObjects.isEmpty else { print("Object detector returned no results.") return } // ...
Objective-C
NSError *error; NSArray<FIRVisionObject *> *objects = [objectDetector resultsInImage:image error:&error]; if (error == nil) { return; } if (objects == nil | objects.count == 0) { // No objects detected. return; } // Success. Get object info here. // ...
Se a chamada para o processador de imagem for bem-sucedida, ela transmitirá uma lista de
VisionObject
para o gerenciador de conclusão ou retornará a lista, caso você tenha chamado o método assíncrono ou síncrono.Cada
VisionObject
contém as seguintes propriedades:frame
Um CGRect
que indica a posição do objeto na imagem.trackingID
Um número inteiro que identifica o objeto nas imagens. Nulo no modo de imagem única. classificationCategory
A categoria abrangente do objeto. Se o detector de objetos não tiver a classificação ativada, isso será sempre .unknown
.confidence
O nível de confiança da classificação do objeto. Se o detector de objetos não tiver a classificação ativada ou o objeto for classificado como desconhecido, isso será nil
.Swift
// detectedObjects contains one item if multiple object detection wasn't enabled. for obj in detectedObjects { let bounds = obj.frame let id = obj.trackingID // If classification was enabled: let category = obj.classificationCategory let confidence = obj.confidence }
Objective-C
// The list of detected objects contains one item if multiple // object detection wasn't enabled. for (FIRVisionObject *obj in objects) { CGRect bounds = obj.frame; if (obj.trackingID) { NSInteger id = obj.trackingID.integerValue; } // If classification was enabled: FIRVisionObjectCategory category = obj.classificationCategory; float confidence = obj.confidence.floatValue; }
Como melhorar a usabilidade e o desempenho
Para a melhor experiência do usuário, siga estas diretrizes no aplicativo:
- A detecção bem-sucedida de objetos depende da complexidade visual do objeto. Objetos com um pequeno número de recursos visuais podem precisar ocupar uma parte maior da imagem a ser detectada. Forneça aos usuários orientações sobre como capturar entradas que funcionem bem com o tipo de objeto que você quer detectar.
- Ao usar a classificação, se você quiser detectar objetos que não se enquadrem nas categorias suportadas, implemente o tratamento especial para objetos desconhecidos.
Além disso, confira o conjunto de [app de demonstração do Material Design do Kit de ML][showcase-link]{: .external} e a coleção Padrões de recursos de machine learning do Material Design.
Ao usar o modo de streaming em um aplicativo em tempo real, siga estas diretrizes para alcançar 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 será capaz de produzir taxas de frames adequadas.
Desative a classificação se ela não for necessária.
- Limite as chamadas ao detector. Se um novo frame de vídeo ficar disponível durante a execução do detector, descarte esse frame.
- Se você estiver usando a saída do detector para sobrepor elementos gráficos na imagem de entrada, primeiro acesse o resultado do Kit de ML. Em seguida, renderize a imagem e faça a sobreposição de uma só vez. Ao fazer isso, você renderiza a superfície de exibição apenas uma vez para cada frame de entrada. Consulte as classes previewOverlayView e FIRDetectionOverlayView no app de exemplo da demonstração.