É possível usar o Kit de ML para reconhecer entidades em uma imagem e rotulá-las. Essa API é compatível com uma ampla variedade de modelos de classificação de imagem personalizados. Consulte Modelos personalizados com o Kit de ML para orientação sobre requisitos de compatibilidade de modelos, onde encontrar modelos pré-treinados e como treinar seus próprios modelos.
Há duas maneiras de integrar um modelo personalizado. Coloque o modelo na pasta de recursos do app para agrupar o modelo ou faça o download dele dinamicamente do Firebase. A tabela a seguir compara as duas opções.
Modelo em pacote | Modelo hospedado |
---|---|
O modelo faz parte do APK do seu app, que aumenta o tamanho dele. | O modelo não faz parte do seu APK. Ele é 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 |
É preciso republicar seu app para atualizar o modelo | Enviar atualizações do modelo sem republicar o app |
Sem testes A/B integrados | Teste A/B fácil com a Configuração remota do Firebase |
Testar
- Consulte o app de início rápido do Vision para ver um exemplo de uso do modelo empacotado e o aplicativo de início rápido do AutoML para um exemplo de uso do modelo hospedado.
Antes de começar
Inclua as bibliotecas do Kit de ML no seu Podfile:
Para agrupar um modelo e seu app:
pod 'GoogleMLKit/ImageLabelingCustom', '3.2.0'
Para fazer o download dinâmico de um modelo do Firebase, adicione a dependência
LinkFirebase
:pod 'GoogleMLKit/ImageLabelingCustom', '3.2.0' pod 'GoogleMLKit/LinkFirebase', '3.2.0'
Depois de instalar ou atualizar os pods do projeto, abra o projeto Xcode usando o
.xcworkspace
. O Kit de ML é compatível com a versão 13.2.1 ou posterior 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 empacotar 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 (que geralmente termina em
.tflite
ou.lite
) para o projeto do Xcode. SelecioneCopy 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 modelo hospedada no Firebase
Para usar o modelo hospedado remotamente, crie um objeto RemoteModel
, 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.
Configurar o rotulador de imagens
Depois de configurar as origens do modelo, crie um objeto ImageLabeler
usando uma
delas.
As seguintes opções estão disponíveis:
Opções | |
---|---|
confidenceThreshold
|
Pontuação de confiança mínima dos rótulos detectados. Se não for definido, qualquer 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, um limite padrão de 0,0 será usado. |
maxResultCount
|
Número máximo de rótulos a serem retornados. Se não for definido, o valor padrão 10 será usado. |
Se você tiver apenas um modelo agrupado localmente, basta criar um rotulador usando o
objeto LocalModel
:
Swift
let options = CustomImageLabelerOptions(localModel: localModel) options.confidenceThreshold = NSNumber(value: 0.0) let imageLabeler = ImageLabeler.imageLabeler(options: options)
Objective-C
MLKCustomImageLabelerOptions *options = [[MLKCustomImageLabelerOptions alloc] initWithLocalModel:localModel]; options.confidenceThreshold = @(0.0); 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 isso só precise ser confirmado antes de executar o rotulador, se você
tiver um modelo hospedado remotamente e um modelo empacotado localmente, pode fazer
sentido fazer essa verificação ao instanciar o ImageLabeler
: crie um
rotulador usando o modelo remoto se ele tiver sido transferido por download. Caso contrário, faça isso usando o modelo local.
Swift
var options: CustomImageLabelerOptions! if (ModelManager.modelManager().isModelDownloaded(remoteModel)) { options = CustomImageLabelerOptions(remoteModel: remoteModel) } else { options = CustomImageLabelerOptions(localModel: localModel) } options.confidenceThreshold = NSNumber(value: 0.0) let imageLabeler = ImageLabeler.imageLabeler(options: options)
Objective-C
MLKCustomImageLabelerOptions *options; if ([[MLKModelManager modelManager] isModelDownloaded:remoteModel]) { options = [[MLKCustomImageLabelerOptions alloc] initWithRemoteModel:remoteModel]; } else { options = [[MLKCustomImageLabelerOptions alloc] initWithLocalModel:localModel]; } options.confidenceThreshold = @(0.0); 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.
Para receber o status de download do modelo, anexe observadores à Central de
Notificações padrão. Certifique-se de usar uma referência fraca a self
no bloco de
observadores, já que os downloads podem levar 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]; }];
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 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];
3. Executar o rotulador de imagens
Para rotular objetos em uma imagem, transmita o objeto image
para o método
process()
do ImageLabeler
.
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 (label.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 entidades rotuladas
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 na funçãocaptureOutput(_, didOutput:from:)
deAVCaptureVideoDataOutputSampleBufferDelegate
para receber resultados de forma síncrona do frame de vídeo especificado. Mantenha oalwaysDiscardsLateVideoFrames
deAVCaptureVideoDataOutput
comotrue
para limitar as chamadas ao detector. Se um novo frame de vídeo ficar disponível 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.