Após treinar seu próprio modelo com o AutoML Vision Edge, use esse modelo no seu app para rotular imagens.
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/MLVisionAutoML', '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. Carregar o modelo
O Kit de ML executa seus modelos gerados pelo AutoML no dispositivo. No entanto, é possível configurar o Kit para carregar seu modelo remotamente a partir do Firebase, do armazenamento local ou de ambos.
Com a hospedagem no Firebase, você pode atualizar o modelo sem liberar uma nova versão do app, além de usar a Configuração remota e os Testes A/B para exibir dinamicamente modelos diferentes para diversos conjuntos de usuários.
Se você optar por fornecer o modelo hospedando-o apenas com o Firebase, sem agrupá-lo com o app, é possível reduzir o tamanho do download inicial do aplicativo. No entanto, se o modelo não estiver agrupado com o app, nenhuma função relacionada a ele vai estar disponível até que o app faça o download do modelo pela primeira vez.
Ao agrupar o modelo e o aplicativo, é possível garantir que os recursos de ML do aplicativo ainda funcionem quando o modelo hospedado pelo Firebase não estiver disponível.
Configurar uma fonte de modelo hospedada no Firebase
Para usar o modelo hospedado remotamente, crie um objeto AutoMLRemoteModel
, especificando o nome que você atribuiu ao modelo quando o publicou:
Swift
let remoteModel = AutoMLRemoteModel(
name: "your_remote_model" // The name you assigned in the Firebase console.
)
Objective-C
FIRAutoMLRemoteModel *remoteModel = [[FIRAutoMLRemoteModel alloc]
initWithName:@"your_remote_model"]; // The name you assigned in the Firebase console.
Em seguida, inicie a tarefa de download do modelo, especificando as condições de acordo com 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 maneira assíncrona no Firebase:
Swift
let downloadConditions = ModelDownloadConditions(
allowsCellularAccess: true,
allowsBackgroundDownloading: true
)
let downloadProgress = ModelManager.modelManager().download(
remoteModel,
conditions: downloadConditions
)
Objective-C
FIRModelDownloadConditions *downloadConditions =
[[FIRModelDownloadConditions alloc] initWithAllowsCellularAccess:YES
allowsBackgroundDownloading:YES];
NSProgress *downloadProgress =
[[FIRModelManager modelManager] downloadRemoteModel: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.
Configurar uma fonte de modelo local
Para agrupar o modelo e o aplicativo, siga estas etapas:
- Extraia o modelo e os metadados dele do arquivo ZIP que você salvou do Firebase console em uma pasta:
your_model_directory |____dict.txt |____manifest.json |____model.tflite
Os três arquivos precisam estar na mesma pasta. Recomendamos usar os arquivos da maneira como foram salvos no download, sem fazer alterações neles, inclusive nos nomes. - Copie a pasta para seu projeto do Xcode, selecionando Criar referências de pasta ao fazer isso. O arquivo de modelo e os metadados serão incluídos no pacote de apps e estarão disponíveis para o Kit de ML.
- Crie um objeto
AutoMLLocalModel
, especificando o caminho para o arquivo de manifesto do modelo:Swift
guard let manifestPath = Bundle.main.path( forResource: "manifest", ofType: "json", inDirectory: "your_model_directory" ) else { return true } let localModel = AutoMLLocalModel(manifestPath: manifestPath)
Objective-C
NSString *manifestPath = [NSBundle.mainBundle pathForResource:@"manifest" ofType:@"json" inDirectory:@"your_model_directory"]; FIRAutoMLLocalModel *localModel = [[FIRAutoMLLocalModel alloc] initWithManifestPath:manifestPath];
Criar um rotulador de imagens a partir do modelo
Depois de configurar as origens do modelo, crie um objeto VisionImageLabeler
a partir de uma delas.
Se você tiver apenas um modelo agrupado localmente, basta criar um rotulador a partir do objeto AutoMLLocalModel
e configurar o limite de pontuação de confiança que você quer exigir. Consulte Avaliar seu modelo:
Swift
let options = VisionOnDeviceAutoMLImageLabelerOptions(localModel: localModel)
options.confidenceThreshold = 0 // Evaluate your model in the Firebase console
// to determine an appropriate value.
let labeler = Vision.vision().onDeviceAutoMLImageLabeler(options: options)
Objective-C
FIRVisionOnDeviceAutoMLImageLabelerOptions *options =
[[FIRVisionOnDeviceAutoMLImageLabelerOptions alloc] initWithLocalModel:localModel];
options.confidenceThreshold = 0; // Evaluate your model in the Firebase console
// to determine an appropriate value.
FIRVisionImageLabeler *labeler =
[[FIRVision vision] onDeviceAutoMLImageLabelerWithOptions:options];
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 você só precise confirmar isso antes de executar o rotulador, se você
tiver um modelo hospedado remotamente e um modelo agrupado localmente,
é útil fazer essa verificação ao instanciar o VisionImageLabeler
. Crie
um rotulador a partir do modelo remoto, se já tiver feito o download, ou senão a partir do
modelo local.
Swift
var options: VisionOnDeviceAutoMLImageLabelerOptions?
if (ModelManager.modelManager().isModelDownloaded(remoteModel)) {
options = VisionOnDeviceAutoMLImageLabelerOptions(remoteModel: remoteModel)
} else {
options = VisionOnDeviceAutoMLImageLabelerOptions(localModel: localModel)
}
options.confidenceThreshold = 0 // Evaluate your model in the Firebase console
// to determine an appropriate value.
let labeler = Vision.vision().onDeviceAutoMLImageLabeler(options: options)
Objective-C
VisionOnDeviceAutoMLImageLabelerOptions *options;
if ([[FIRModelManager modelManager] isModelDownloaded:remoteModel]) {
options = [[FIRVisionOnDeviceAutoMLImageLabelerOptions alloc] initWithRemoteModel:remoteModel];
} else {
options = [[FIRVisionOnDeviceAutoMLImageLabelerOptions alloc] initWithLocalModel:localModel];
}
options.confidenceThreshold = 0.0f; // Evaluate your model in the Firebase console
// to determine an appropriate value.
FIRVisionImageLabeler *labeler = [[FIRVision vision] onDeviceAutoMLImageLabelerWithOptions:options];
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.
Também é possível receber o status de download do modelo. Para fazer isso, basta enviar observadores à Central de Notificações padrão: Use uma referência fraca a self
no bloco de
observadores, já que os downloads podem demorar um pouco, e o objeto de origem vai ser
liberado quando o download for concluído. Exemplo:
Swift
NotificationCenter.default.addObserver( forName: .firebaseMLModelDownloadDidSucceed, 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: .firebaseMLModelDownloadDidFail, 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:FIRModelDownloadDidSucceedNotification object:nil queue:nil usingBlock:^(NSNotification *_Nonnull note) { if (weakSelf == nil | note.userInfo == nil) { return; } __strong typeof(self) strongSelf = weakSelf; FIRRemoteModel *model = note.userInfo[FIRModelDownloadUserInfoKeyRemoteModel]; if ([model.name isEqualToString:@"your_remote_model"]) { // The model was downloaded and is available on the device } }]; [NSNotificationCenter.defaultCenter addObserverForName:FIRModelDownloadDidFailNotification object:nil queue:nil usingBlock:^(NSNotification *_Nonnull note) { if (weakSelf == nil | note.userInfo == nil) { return; } __strong typeof(self) strongSelf = weakSelf; NSError *error = note.userInfo[FIRModelDownloadUserInfoKeyError]; }];
2. Preparar a imagem de entrada
Em seguida, para cada imagem que você quer rotular, crie um objeto VisionImage
usando uma das opções descritas nesta seção e transmita-o para uma instância de VisionImageLabeler
(descrita na próxima seção).
Crie um objeto VisionImage
usando um UIImage
ou um CMSampleBufferRef
.
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;
3. Executar o rotulador de imagens
Para rotular objetos em uma imagem, transmita o objeto VisionImage
para o método process()
do VisionImageLabeler
:
Swift
labeler.process(image) { labels, error in
guard error == nil, let labels = labels else { return }
// Task succeeded.
// ...
}
Objective-C
[labeler
processImage:image
completion:^(NSArray<FIRVisionImageLabel *> *_Nullable labels, NSError *_Nullable error) {
if (error != nil || labels == nil) {
return;
}
// Task succeeded.
// ...
}];
Se a rotulagem da imagem for bem-sucedida, uma matriz de objetos VisionImageLabel
será transmitida para o gerenciador de conclusão. Você pode receber informações sobre um recurso reconhecido na imagem em cada objeto.
Por exemplo:
Swift
for label in labels {
let labelText = label.text
let confidence = label.confidence
}
Objective-C
for (FIRVisionImageLabel *label in labels) {
NSString *labelText = label.text;
NSNumber *confidence = label.confidence;
}
Dicas para melhorar o desempenho em tempo real
- 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.