Rotular imagens com um modelo treinado pelo AutoML no iOS
Depois de treinar seu próprio modelo usando o AutoML Vision Edge, você poderá usá-lo 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 ver um exemplo de uso dessa API.
Antes de começar
1. Inclua as bibliotecas do kit de ML no seu Podfile:Para empacotar um modelo e seu app:
pod 'GoogleMLKit/ImageLabelingAutoML'
LinkFirebase
:
pod 'GoogleMLKit/ImageLabelingAutoML' pod 'GoogleMLKit/LinkFirebase'
.xcworkspace
. O ML Kit é compatível com o Xcode
versão 13.2.1 ou mais recente.
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 e o app, siga estas etapas:1. Extraia o modelo e os metadados dele do arquivo ZIP que você baixou 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:
Swift
guard let manifestPath = Bundle.main.path( forResource: "manifest", ofType: "json", inDirectory: "your_model_directory" ) else { return } let localModel = AutoMLImageLabelerLocalModel(manifestPath: manifestPath)
Objective-C
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:
Swift
let remoteModel = AutoMLImageLabelerRemoteModel( name: "your_remote_model" // The name you assigned in // the Firebase console. )
Objective-C
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:
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.
Criar um rotulador de imagens do 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 usando o objeto AutoMLImageLabelerLocalModel
e configurar o limite de pontuação de confiança que você quer exigir. Consulte Avaliar seu modelo:
Swift
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)
Objective-C
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 tiver um modelo hospedado remotamente e um agrupado localmente, talvez seja interessante fazer essa verificação ao instanciar o ImageLabeler
: crie um rotulador com o modelo remoto se ele tiver sido baixado e com o modelo local caso contrário.
Swift
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)
Objective-C
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 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: .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]; }];
2. 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 a.orientation
correta.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 no
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];
3. Executar o rotulador de imagens
De forma assíncrona:
Swift
imageLabeler.process(image) { labels, error in guard error == nil, let labels = labels, !labels.isEmpty else { // Handle the error. return } // Show results. }
Objective-C
[imageLabeler processImage:image completion:^(NSArray*_Nullable labels, NSError *_Nullable error) { if (labels.count == 0) { // Handle the error. return; } // Show results. }];
De forma síncrona:
Swift
var labels: [ImageLabel] do { labels = try imageLabeler.results(in: image) } catch let error { // Handle the error. return } // Show results.
Objective-C
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:
Swift
for label in labels { let labelText = label.text let confidence = label.confidence let index = label.index }
Objective-C
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çãoAVCaptureVideoDataOutputSampleBufferDelegate
captureOutput(_, didOutput:from:)
para receber de forma síncrona os resultados do frame de vídeo específico. Mantenha oalwaysDiscardsLateVideoFrames
doAVCaptureVideoDataOutput
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 frame de entrada processado. Consulte updatePreviewOverlayViewWithLastFrame na amostra do guia de início rápido do Kit de ML para conferir um exemplo.