Rotular imagens com um modelo treinado pelo AutoML no iOS
Depois de treinar seu próprio modelo usando o AutoML Vision Edge, use-o no app para rotular imagens.
Há duas maneiras de integrar modelos treinados pelo AutoML Vision Edge. Você pode empacotar o modelo copiando os arquivos dele para seu projeto do Xcode ou fazer o download dele dinamicamente do Firebase.
Opções de empacotamento de modelos | |
---|---|
Incluído no seu app |
|
Hospedado com o Firebase |
|
Faça um teste
- Teste o app de exemplo para conferir um exemplo de uso dessa API.
Antes de começar
1. Inclua as bibliotecas do kit de ML no seu Podfile:Para agrupar um modelo com o app:
pod 'GoogleMLKit/ImageLabelingAutoML'
LinkFirebase
:
pod 'GoogleMLKit/ImageLabelingAutoML' pod 'GoogleMLKit/LinkFirebase'
.xcworkspace
code>. O Kit de ML tem suporte à versão
13.2.1 ou mais recente do Xcode.
3. 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 empacotar o
modelo.
1. Carregar o modelo
Configurar uma fonte de modelo local
Para agrupar o modelo com o app:1. Extraia o modelo e os metadados dele do arquivo ZIP que você salvou do Console do Firebase para uma pasta:
your_model_directory |____dict.txt |____manifest.json |____model.tflite
2. 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.
3. Crie o objeto
AutoMLImageLabelerLocalModel
, especificando o caminho para o
arquivo de manifesto do modelo:
guard let manifestPath = Bundle.main.path( forResource: "manifest", ofType: "json", inDirectory: "your_model_directory" ) else { return } let localModel = AutoMLImageLabelerLocalModel(manifestPath: manifestPath)
NSString *manifestPath = [NSBundle.mainBundle pathForResource:@"manifest" ofType:@"json" inDirectory:@"your_model_directory"]; MLKAutoMLImageLabelerLocalModel *localModel = [[MLKAutoMLImageLabelerLocalModel alloc] initWithManifestPath:manifestPath];
Configurar uma fonte de modelo hospedada no Firebase
Para usar o modelo hospedado remotamente, crie um objeto AutoMLImageLabelerRemoteModel
, especificando o nome que você atribuiu ao modelo quando o publicou:
let remoteModel = AutoMLImageLabelerRemoteModel( name: "your_remote_model" // The name you assigned in // the Firebase console. )
MLKAutoMLImageLabelerRemoteModel *remoteModel = [[MLKAutoMLImageLabelerRemoteModel 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 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:
let downloadConditions = ModelDownloadConditions( allowsCellularAccess: true, allowsBackgroundDownloading: true ) let downloadProgress = ModelManager.modelManager().download( remoteModel, conditions: downloadConditions )
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.
Criar um rotulador de imagens usando o modelo
Depois de configurar as origens do modelo, crie um objeto ImageLabeler
usando uma
delas.
Se você tiver apenas um modelo agrupado localmente, basta criar um rotulador a partir do
objeto AutoMLImageLabelerLocalModel
e configurar o limite de pontuação de confiança
que você quer exigir. Consulte Avaliar seu modo:
let options = AutoMLImageLabelerOptions(localModel: localModel) options.confidenceThreshold = NSNumber(value: 0.0) // Evaluate your model in the Firebase console // to determine an appropriate value. let imageLabeler = ImageLabeler.imageLabeler(options: options)
MLKAutoMLImageLabelerOptions *options = [[MLKAutoMLImageLabelerOptions alloc] initWithLocalModel:localModel]; options.confidenceThreshold = @(0.0); // Evaluate your model in the Firebase console // to determine an appropriate value. MLKImageLabeler *imageLabeler = [MLKImageLabeler imageLabelerWithOptions: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, pode ser
ótimo realizar essa verificação ao instanciar o ImageLabeler
: crie um
rotulador usando o modelo remoto se ele tiver sido feito o download e o modelo local
caso contrário.
var options: AutoMLImageLabelerOptions! if (ModelManager.modelManager().isModelDownloaded(remoteModel)) { options = AutoMLImageLabelerOptions(remoteModel: remoteModel) } else { options = AutoMLImageLabelerOptions(localModel: localModel) } options.confidenceThreshold = NSNumber(value: 0.0) // Evaluate your model in the Firebase console // to determine an appropriate value. let imageLabeler = ImageLabeler.imageLabeler(options: options)
MLKAutoMLImageLabelerOptions *options; if ([[MLKModelManager modelManager] isModelDownloaded:remoteModel]) { options = [[MLKAutoMLImageLabelerOptions alloc] initWithRemoteModel:remoteModel]; } else { options = [[MLKAutoMLImageLabelerOptions alloc] initWithLocalModel:localModel]; } options.confidenceThreshold = @(0.0); // Evaluate your model in the Firebase console // to determine an appropriate value. MLKImageLabeler *imageLabeler = [MLKImageLabeler imageLabelerWithOptions:options];
Se você tiver apenas um modelo hospedado remotamente, desative o recurso relacionado ao modelo (por exemplo, ocultando ou esmaecendo parte da interface) 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 para self
no bloco de
observadores, já que os downloads podem demorar um pouco, e o objeto de origem pode ser
liberado quando o download for concluído. Exemplo:
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] // ... }
__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]; }];
2. Preparar a imagem de entrada
Crie um objeto VisionImage
usando um UIImage
ou um
CMSampleBuffer
.
Se você usar um UIImage
, siga estas etapas:
- Crie um objeto
VisionImage
com oUIImage
. Especifique a.orientation
correta.let image = VisionImage(image: UIImage) visionImage.orientation = image.imageOrientation
MLKVisionImage *visionImage = [[MLKVisionImage alloc] initWithImage:image]; visionImage.orientation = image.imageOrientation;
Se você usar um CMSampleBuffer
, siga estas etapas:
-
Especifique a orientação dos dados da imagem contidos no
CMSampleBuffer
.Para conferir a orientação da imagem:
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 } }
- (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:let image = VisionImage(buffer: sampleBuffer) image.orientation = imageOrientation( deviceOrientation: UIDevice.current.orientation, cameraPosition: cameraPosition)
MLKVisionImage *image = [[MLKVisionImage alloc] initWithBuffer:sampleBuffer]; image.orientation = [self imageOrientationFromDeviceOrientation:UIDevice.currentDevice.orientation cameraPosition:cameraPosition];
3. Executar o rotulador de imagens
De forma assíncrona:
imageLabeler.process(image) { labels, error in guard error == nil, let labels = labels, !labels.isEmpty else { // Handle the error. return } // Show results. }
[imageLabeler processImage:image completion:^(NSArray*_Nullable labels, NSError *_Nullable error) { if (labels.count == 0) { // Handle the error. return; } // Show results. }];
De forma síncrona:
var labels: [ImageLabel] do { labels = try imageLabeler.results(in: image) } catch let error { // Handle the error. return } // Show results.
NSError *error; NSArray*labels = [imageLabeler resultsInImage:image error:&error]; // Show results or handle the error.
4. Receber informações sobre objetos rotulados
Se a operação de rotulagem de imagem for bem-sucedida, ela retornará uma matriz deImageLabel
. Cada ImageLabel
representa algo que foi
rotulado na imagem. É possível receber a descrição de texto de cada rótulo (se disponível nos
metadados do arquivo de modelo do TensorFlow Lite), a pontuação de confiança e o índice.
Exemplo:
for label in labels { let labelText = label.text let confidence = label.confidence let index = label.index }
for (MLKImageLabel *label in labels) { NSString *labelText = label.text; float confidence = label.confidence; NSInteger index = label.index; }
Dicas para melhorar o desempenho em tempo real
Caso você queira rotular imagens em um aplicativo em tempo real, siga estas diretrizes para ter as melhores taxas de frames:
- Para processar frames de vídeo, use a API síncrona
results(in:)
do detector. Chame esse método da funçãocaptureOutput(_, didOutput:from:)
doAVCaptureVideoDataOutputSampleBufferDelegate
para receber resultados síncronos do quadro de vídeo fornecido. Mantenha oAVCaptureVideoDataOutput
dealwaysDiscardsLateVideoFrames
comotrue
para limitar as chamadas ao detector. Se um novo frame de vídeo ficar disponível durante a execução do detector, 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. 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 quadro de entrada processado. Consulte updatePreviewOverlayViewWithLastFrame no exemplo do guia de início rápido do Kit de ML.