Você pode usar o ML Kit para detectar e rastrear objetos em quadros de vídeo.
Quando você passa imagens do ML Kit, o ML Kit retorna, para cada imagem, uma lista de até cinco objetos detectados e sua posição na imagem. Ao detectar objetos em fluxos de vídeo, cada objeto possui um ID que você pode usar para rastreá-lo nas imagens. Opcionalmente, você também pode ativar a classificação aproximada de objetos, que rotula os objetos com descrições amplas de categorias.
Antes de você começar
- Se você ainda não adicionou o Firebase ao seu aplicativo, faça isso seguindo as etapas do guia de primeiros passos .
- Inclua as bibliotecas do ML Kit em seu Podfile:
pod 'Firebase/MLVision', '6.25.0' pod 'Firebase/MLVisionObjectDetection', '6.25.0'
Depois de instalar ou atualizar os pods do seu projeto, certifique-se de abrir seu projeto Xcode usando seu.xcworkspace
. - No seu aplicativo, importe o Firebase:
Rápido
import Firebase
Objetivo-C
@import Firebase;
1. Configure o detector de objetos
Para começar a detectar e rastrear objetos, primeiro crie uma instância de VisionObjectDetector
, especificando opcionalmente quaisquer configurações de detector que você deseja alterar do padrão.
Configure o detector de objetos para seu caso de uso com um objeto
VisionObjectDetectorOptions
. Você pode alterar as seguintes configurações:Configurações do detector de objetos Modo de detecção .stream
(padrão) |.singleImage
No modo de fluxo (padrão), o detector de objetos é executado com latência muito baixa, mas pode produzir resultados incompletos (como caixas delimitadoras ou categorias não especificadas) nas primeiras invocações do detector. Além disso, no modo de fluxo, o detector atribui IDs de rastreamento a objetos, que você pode usar para rastrear objetos entre quadros. Use este modo quando quiser rastrear objetos ou quando a baixa latência for importante, como ao processar fluxos de vídeo em tempo real.
No modo de imagem única, o detector de objetos aguarda até que a caixa delimitadora do objeto detectado e a categoria (se você tiver habilitado a classificação) estejam disponíveis antes de retornar um resultado. Como consequência, a latência de detecção é potencialmente maior. Além disso, no modo de imagem única, os IDs de rastreamento não são atribuídos. Use este modo se a latência não for crítica e você não quiser lidar com resultados parciais.
Detecte e rastreie vários objetos false
(padrão) |true
Seja para detectar e rastrear até cinco objetos ou apenas o objeto mais proeminente (padrão).
Classificar objetos false
(padrão) |true
Se deve ou não classificar os objetos detectados em categorias grosseiras. Quando ativado, o detector de objetos classifica os objetos nas seguintes categorias: produtos de moda, alimentos, produtos domésticos, lugares, plantas e desconhecidos.
A API de detecção e rastreamento de objetos é otimizada para estes dois casos de uso principais:
- Detecção e rastreamento ao vivo 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 estes casos de uso:
Rápido
// 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
Objetivo-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
Obtenha uma instância do
FirebaseVisionObjectDetector
:Rápido
let objectDetector = Vision.vision().objectDetector() // Or, to change the default settings: let objectDetector = Vision.vision().objectDetector(options: options)
Objetivo-C
FIRVisionObjectDetector *objectDetector = [[FIRVision vision] objectDetector]; // Or, to change the default settings: FIRVisionObjectDetector *objectDetector = [[FIRVision vision] objectDetectorWithOptions:options];
2. Execute o detector de objetos
Para detectar e rastrear objetos, faça o seguinte para cada imagem ou quadro de vídeo. Se você ativou o modo de fluxo, deverá criar objetos VisionImage
a partir de CMSampleBufferRef
s.
Crie um objeto
VisionImage
usandoUIImage
ouCMSampleBufferRef
.Para usar uma
UIImage
:- Se necessário, gire a imagem para que sua propriedade
imageOrientation
seja.up
. - Crie um objeto
VisionImage
usando oUIImage
girado corretamente. Não especifique nenhum metadado de rotação — o valor padrão,.topLeft
, deve ser usado.Rápido
let image = VisionImage(image: uiImage)
Objetivo-C
FIRVisionImage *image = [[FIRVisionImage alloc] initWithImage:uiImage];
Para usar um
CMSampleBufferRef
:Crie um objeto
VisionImageMetadata
que especifique a orientação dos dados de imagem contidos no bufferCMSampleBufferRef
.Para obter a orientação da imagem:
Rápido
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 } }
Objetivo-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:
Rápido
let cameraPosition = AVCaptureDevice.Position.back // Set to the capture device you used. let metadata = VisionImageMetadata() metadata.orientation = imageOrientation( deviceOrientation: UIDevice.current.orientation, cameraPosition: cameraPosition )
Objetivo-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:Rápido
let image = VisionImage(buffer: sampleBuffer) image.metadata = metadata
Objetivo-C
FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer]; image.metadata = metadata;
- Se necessário, gire a imagem para que sua propriedade
Passe o
VisionImage
para um dos métodos de processamento de imagem do detector de objetos. Você pode usar o método assíncronoprocess(image:)
ou o método síncronoresults()
.Para detectar objetos de forma assíncrona:
Rápido
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. // ... }
Objetivo-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 forma síncrona:
Rápido
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 } // ...
Objetivo-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, ele passará uma lista de
VisionObject
s para o manipulador de conclusão ou retornará a lista, dependendo se você chamou 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 inteiro que identifica o objeto nas imagens. Nulo no modo de imagem única. classificationCategory
A categoria grosseira do objeto. Se o detector de objetos não tiver a classificação habilitada, será sempre .unknown
.confidence
O valor de confiança da classificação do objeto. Se o detector de objetos não tiver a classificação habilitada ou o objeto for classificado como desconhecido, isso será nil
.Rápido
// 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 }
Objetivo-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; }
Melhorando a usabilidade e o desempenho
Para obter a melhor experiência do usuário, siga estas diretrizes em seu aplicativo:
- A detecção bem-sucedida de objetos depende da complexidade visual do objeto. Objetos com um pequeno número de características visuais podem precisar ocupar uma parte maior da imagem para serem detectados. Você deve fornecer aos usuários orientações sobre como capturar entradas que funcionem bem com o tipo de objetos que você deseja detectar.
- Ao usar a classificação, se você quiser detectar objetos que não se enquadram perfeitamente nas categorias suportadas, implemente um tratamento especial para objetos desconhecidos.
Além disso, confira o [aplicativo de demonstração do ML Kit Material Design][showcase-link]{: .external } e a coleção de recursos do Material Design Patterns para aprendizado de máquina .
Ao usar o modo de streaming em um aplicativo em tempo real, siga estas diretrizes para obter as melhores taxas de quadros:
Não use a detecção de múltiplos objetos no modo de streaming, pois a maioria dos dispositivos não será capaz de produzir taxas de quadros adequadas.
Desative a classificação se não precisar dela.
- Limite as chamadas para o detector. Se um novo quadro de vídeo ficar disponível enquanto o detector estiver em execução, elimine o quadro.
- Se você estiver usando a saída do detector para sobrepor gráficos na imagem de entrada, primeiro obtenha 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 na superfície de exibição apenas uma vez para cada quadro de entrada. Veja as classes previewOverlayView e FIRDetectionOverlayView no aplicativo de exemplo de demonstração para ver um exemplo.