Quando você transmite uma imagem para o Kit de ML, ela detecta até cinco objetos e a posição de cada um 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 um frame a outro.
É possível usar um modelo de classificação de imagem personalizado para classificar os objetos detectados. Consulte Modelos personalizados com kit de ML para ver orientações sobre requisitos de compatibilidade de modelo, onde encontrar modelos pré-treinados e como treinar seus próprios modelos.
Há duas maneiras de integrar um modelo personalizado. Você pode agrupar o modelo colocando-o na pasta de recursos do app ou fazendo o download dele dinamicamente do Firebase. A tabela a seguir compara as duas opções.
Modelo agrupado | Modelo hospedado |
---|---|
O modelo faz parte do arquivo .ipa do app, que
aumenta o tamanho dele. |
O modelo não faz parte do arquivo .ipa do app. É
hospedado ao fazer upload para o
Firebase Machine Learning. |
O modelo estará disponível imediatamente, mesmo quando o dispositivo Android estiver off-line | O download do modelo é feito sob demanda |
Não é necessário ter um projeto do Firebase | Requer um projeto do Firebase |
É necessário publicar o app novamente para atualizar o modelo | Enviar atualizações do modelo sem republicar o app |
Nenhum teste A/B integrado | Teste A/B fácil com a Configuração remota do Firebase. |
Faça um teste
- Consulte o app de início rápido do Vision para ver um exemplo de uso do modelo em pacote e o app de início rápido do Automl para um exemplo de uso do modelo hospedado.
- Consulte o app de demonstração do Material Design (em inglês) para ver uma implementação completa dessa API.
Antes de começar
Inclua as bibliotecas do kit de ML no seu Podfile:
Para empacotar um modelo e seu app:
pod 'GoogleMLKit/ObjectDetectionCustom', '3.2.0'
Para fazer o download dinâmico de um modelo do Firebase, adicione a dependência
LinkFirebase
:pod 'GoogleMLKit/ObjectDetectionCustom', '3.2.0' pod 'GoogleMLKit/LinkFirebase', '3.2.0'
Depois de instalar ou atualizar os pods do projeto, abra o projeto do Xcode usando o
.xcworkspace
. O Kit de ML é compatível com a versão 13.2.1 ou mais recente do Xcode.Se você quiser fazer o download de um modelo, adicione o Firebase ao seu projeto do iOS, caso ainda não tenha feito isso. Essa etapa não é necessária para agrupar o modelo.
1. Carregar o modelo
Configurar uma fonte de modelo local
Para agrupar o modelo e o aplicativo, siga estas etapas:
Copie o arquivo de modelo (geralmente terminando em
.tflite
ou.lite
) para o projeto Xcode, selecionandoCopy bundle resources
ao fazer isso. O arquivo de modelo será incluído no pacote de apps e estará disponível para o Kit de ML.Crie o objeto
LocalModel
, especificando o caminho para o arquivo de modelo:Swift
let localModel = LocalModel(path: localModelFilePath)
Objective-C
MLKLocalModel *localModel = [[MLKLocalModel alloc] initWithPath:localModelFilePath];
Configurar uma fonte de modelos hospedada no Firebase
Para usar o modelo hospedado remotamente, crie um objeto CustomRemoteModel
,
especificando o nome que você atribuiu ao modelo quando o publicou:
Swift
let firebaseModelSource = FirebaseModelSource( name: "your_remote_model") // The name you assigned in // the Firebase console. let remoteModel = CustomRemoteModel(remoteModelSource: firebaseModelSource)
Objective-C
MLKFirebaseModelSource *firebaseModelSource = [[MLKFirebaseModelSource alloc] initWithName:@"your_remote_model"]; // The name you assigned in // the Firebase console. MLKCustomRemoteModel *remoteModel = [[MLKCustomRemoteModel alloc] initWithRemoteModelSource:firebaseModelSource];
Em seguida, inicie a tarefa de download do modelo, especificando as condições sob as quais você quer permitir o download. Se o modelo não estiver no dispositivo ou se uma versão mais recente do modelo estiver disponível, a tarefa fará o download do modelo de forma assíncrona do Firebase:
Swift
let downloadConditions = ModelDownloadConditions( allowsCellularAccess: true, allowsBackgroundDownloading: true ) let downloadProgress = ModelManager.modelManager().download( remoteModel, conditions: downloadConditions )
Objective-C
MLKModelDownloadConditions *downloadConditions = [[MLKModelDownloadConditions alloc] initWithAllowsCellularAccess:YES allowsBackgroundDownloading:YES]; NSProgress *downloadProgress = [[MLKModelManager modelManager] downloadModel:remoteModel conditions:downloadConditions];
Muitos apps iniciam a tarefa de download no código de inicialização, mas você pode fazer isso a qualquer momento antes de precisar usar o modelo.
2. Configurar o detector de objetos
Depois de configurar as origens do modelo, configure o detector de objetos para seu
caso de uso com um objeto CustomObjectDetectorOptions
. É possível alterar as
seguintes configurações:
Configurações do detector de objetos | |
---|---|
Modo de detecção |
STREAM_MODE (padrão) | SINGLE_IMAGE_MODE
Em Em |
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 é necessário classificar objetos detectados usando o modelo de classificador personalizado fornecido. Para usar seu modelo de classificação
personalizado, defina-o como |
Limite de confiança da classificação |
Pontuação de confiança mínima dos rótulos detectados. Se não for definido, o limite do classificador especificado pelos metadados do modelo será usado. Se o modelo não contiver metadados ou os metadados não especificarem um limite de classificador, será usado um limite padrão de 0,0. |
Máximo de rótulos por objeto |
Número máximo de rótulos por objeto que o detector retornará. Se não for definido, o valor padrão de 10 será usado. |
Se você tiver apenas um modelo agrupado localmente, basta criar um detector de objetos a partir do objeto LocalModel
:
Swift
let options = CustomObjectDetectorOptions(localModel: localModel) options.detectorMode = .singleImage options.shouldEnableClassification = true options.shouldEnableMultipleObjects = true options.classificationConfidenceThreshold = NSNumber(value: 0.5) options.maxPerObjectLabelCount = 3
Objective-C
MLKCustomObjectDetectorOptions *options = [[MLKCustomObjectDetectorOptions alloc] initWithLocalModel:localModel]; options.detectorMode = MLKObjectDetectorModeSingleImage; options.shouldEnableClassification = YES; options.shouldEnableMultipleObjects = YES; options.classificationConfidenceThreshold = @(0.5); options.maxPerObjectLabelCount = 3;
Se você tiver um modelo hospedado remotamente, será necessário verificar se foi feito
o download dele antes de executá-lo. É possível verificar o status da tarefa de download do modelo usando o método isModelDownloaded(remoteModel:)
do gerenciador de modelos.
Embora isso só precise ser confirmado antes da execução do detector de objetos, se você tiver um modelo hospedado remotamente e um modelo empacotado localmente, talvez seja útil realizar essa verificação ao instanciar o ObjectDetector
: criar um detector a partir do modelo remoto se ele tiver sido transferido por download e a partir do modelo local, caso contrário.
Swift
var options: CustomObjectDetectorOptions! if (ModelManager.modelManager().isModelDownloaded(remoteModel)) { options = CustomObjectDetectorOptions(remoteModel: remoteModel) } else { options = CustomObjectDetectorOptions(localModel: localModel) } options.detectorMode = .singleImage options.shouldEnableClassification = true options.shouldEnableMultipleObjects = true options.classificationConfidenceThreshold = NSNumber(value: 0.5) options.maxPerObjectLabelCount = 3
Objective-C
MLKCustomObjectDetectorOptions *options; if ([[MLKModelManager modelManager] isModelDownloaded:remoteModel]) { options = [[MLKCustomObjectDetectorOptions alloc] initWithRemoteModel:remoteModel]; } else { options = [[MLKCustomObjectDetectorOptions alloc] initWithLocalModel:localModel]; } options.detectorMode = MLKObjectDetectorModeSingleImage; options.shouldEnableClassification = YES; options.shouldEnableMultipleObjects = YES; options.classificationConfidenceThreshold = @(0.5); options.maxPerObjectLabelCount = 3;
Se você tiver apenas um modelo hospedado remotamente, desative o recurso relacionado ao modelo (por exemplo, ocultando ou esmaecendo parte da IU) até confirmar que o download do modelo foi concluído.
Para ver o status de download do modelo, anexe observadores à Central de notificações padrão. Certifique-se de usar uma referência fraca para self
no bloco de observadores,
porque os downloads podem demorar algum tempo e o objeto de origem poderá ser liberado quando o download for concluído. Exemplo:
Swift
NotificationCenter.default.addObserver( forName: .mlkitModelDownloadDidSucceed, object: nil, queue: nil ) { [weak self] notification in guard let strongSelf = self, let userInfo = notification.userInfo, let model = userInfo[ModelDownloadUserInfoKey.remoteModel.rawValue] as? RemoteModel, model.name == "your_remote_model" else { return } // The model was downloaded and is available on the device } NotificationCenter.default.addObserver( forName: .mlkitModelDownloadDidFail, object: nil, queue: nil ) { [weak self] notification in guard let strongSelf = self, let userInfo = notification.userInfo, let model = userInfo[ModelDownloadUserInfoKey.remoteModel.rawValue] as? RemoteModel else { return } let error = userInfo[ModelDownloadUserInfoKey.error.rawValue] // ... }
Objective-C
__weak typeof(self) weakSelf = self; [NSNotificationCenter.defaultCenter addObserverForName:MLKModelDownloadDidSucceedNotification object:nil queue:nil usingBlock:^(NSNotification *_Nonnull note) { if (weakSelf == nil | note.userInfo == nil) { return; } __strong typeof(self) strongSelf = weakSelf; MLKRemoteModel *model = note.userInfo[MLKModelDownloadUserInfoKeyRemoteModel]; if ([model.name isEqualToString:@"your_remote_model"]) { // The model was downloaded and is available on the device } }]; [NSNotificationCenter.defaultCenter addObserverForName:MLKModelDownloadDidFailNotification object:nil queue:nil usingBlock:^(NSNotification *_Nonnull note) { if (weakSelf == nil | note.userInfo == nil) { return; } __strong typeof(self) strongSelf = weakSelf; NSError *error = note.userInfo[MLKModelDownloadUserInfoKeyError]; }];
A API de detecção e rastreamento de objetos é otimizada para os dois casos de uso principais a seguir:
- Detecção em tempo real 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 = CustomObjectDetectorOptions(localModel: localModel) options.shouldEnableClassification = true options.maxPerObjectLabelCount = 3 // Multiple object detection in static images let options = CustomObjectDetectorOptions(localModel: localModel) options.detectorMode = .singleImage options.shouldEnableMultipleObjects = true options.shouldEnableClassification = true options.maxPerObjectLabelCount = 3
Objective-C
// Live detection and tracking MLKCustomObjectDetectorOptions *options = [[MLKCustomObjectDetectorOptions alloc] initWithLocalModel:localModel]; options.shouldEnableClassification = YES; options.maxPerObjectLabelCount = 3; // Multiple object detection in static images MLKCustomObjectDetectorOptions *options = [[MLKCustomObjectDetectorOptions alloc] initWithLocalModel:localModel]; options.detectorMode = MLKObjectDetectorModeSingleImage; options.shouldEnableMultipleObjects = YES; options.shouldEnableClassification = YES; options.maxPerObjectLabelCount = 3;
3. Preparar a imagem de entrada
Crie um objeto VisionImage
usando um UIImage
ou um
CMSampleBuffer
.
Se você usa um UIImage
, siga estas etapas:
- Crie um objeto
VisionImage
com oUIImage
. 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 em
CMSampleBuffer
.Para ver 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 objetoCMSampleBuffer
e a orientação: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];
4. Criar e executar o detector de objetos
Crie um detector de objetos:
Swift
let objectDetector = ObjectDetector.objectDetector(options: options)
Objective-C
MLKObjectDetector *objectDetector = [MLKObjectDetector objectDetectorWithOptions:options];
Em seguida, use o detector:
De forma assíncrona:
Swift
objectDetector.process(image) { objects, error in guard error == nil, let objects = objects, !objects.isEmpty else { // Handle the error. return } // Show results. }
Objective-C
[objectDetector processImage:image completion:^(NSArray
*_Nullable objects, NSError *_Nullable error) { if (objects.count == 0) { // Handle the error. return; } // Show results. }]; De forma síncrona:
Swift
var objects: [Object] do { objects = try objectDetector.results(in: image) } catch let error { // Handle the error. return } // Show results.
Objective-C
NSError *error; NSArray
*objects = [objectDetector resultsInImage:image error:&error]; // Show results or handle the error.
5. Receber informações sobre objetos rotulados
Se a chamada para o processador de imagem for bem-sucedida, ela transmitirá uma lista de
Object
s para o gerenciador de conclusão ou retornará a lista, dependendo se
você chamou 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 na imagem. |
||||||
trackingID |
Um número inteiro que identifica o objeto nas imagens ou "nil" em SINGLE_IMAGE_MODE. | ||||||
labels |
|
Swift
// objects contains one item if multiple object detection wasn't enabled. for object in objects { let frame = object.frame let trackingID = object.trackingID let description = object.labels.enumerated().map { (index, label) in "Label \(index): \(label.text), \(label.confidence), \(label.index)" }.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 garantir uma ótima experiência do usuário
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. Para que sejam detectados, objetos com um pequeno número de recursos visuais podem precisar ocupar uma parte maior da imagem. 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.
Confira também o [app de demonstração do Material Design do Kit de ML][showcase-link]{: .external} e a coleção de Padrões para recursos com tecnologia de machine learning do Material Design.
Melhoria de desempenho
Se você quiser usar a detecção de objetos em um aplicativo em tempo real, siga estas diretrizes para ter as melhores taxas de frames:Ao usar o modo de streaming em um aplicativo em tempo real, não use a detecção de vários objetos, já que a maioria dos dispositivos não poderá produzir taxas de frames adequadas.
- Para processar frames de vídeo, use a API síncrona
results(in:)
do detector. Chame esse método da funçãocaptureOutput(_, didOutput:from:)
deAVCaptureVideoDataOutputSampleBufferDelegate
para receber resultados de maneira síncrona do frame de vídeo especificado. Mantenha oalwaysDiscardsLateVideoFrames
deAVCaptureVideoDataOutput
comotrue
para limitar as chamadas para o detector. Se um novo frame de vídeo for disponibilizado 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 updatePreviewOverlayViewWithLastFrame no exemplo do guia de início rápido do Kit de ML para ver um exemplo.