Etiquete imágenes con un modelo entrenado por AutoML en plataformas Apple

Después de entrenar su propio modelo con AutoML Vision Edge , puede usarlo en su aplicación para etiquetar imágenes.

Hay dos formas de integrar modelos entrenados desde AutoML Vision Edge. Puede agrupar el modelo copiando los archivos del modelo en su proyecto Xcode, o puede descargarlo dinámicamente desde Firebase.

Opciones de agrupación de modelos
Incluido en su aplicación
  • El modelo es parte del paquete.
  • El modelo está disponible de inmediato, incluso cuando el dispositivo Apple está fuera de línea
  • No es necesario un proyecto de Firebase
Alojado con Firebase
  • Aloje el modelo cargándolo en Firebase Machine Learning
  • Reduce el tamaño del paquete de aplicaciones
  • El modelo se descarga bajo demanda.
  • Envía actualizaciones de modelos sin volver a publicar tu aplicación
  • Pruebas A/B sencillas con Firebase Remote Config
  • Requiere un proyecto de Firebase

Antes de que empieces

  1. Incluya las bibliotecas de ML Kit en su Podfile:

    Para agrupar un modelo con su aplicación:

    pod 'GoogleMLKit/ImageLabelingCustom'
    

    Para descargar dinámicamente un modelo de Firebase, agregue la dependencia de LinkFirebase :

    pod 'GoogleMLKit/ImageLabelingCustom'
    pod 'GoogleMLKit/LinkFirebase'
    
  2. Después de instalar o actualizar los Pods de su proyecto, abra su proyecto Xcode usando su .xcworkspace . ML Kit es compatible con Xcode versión 12.2 o superior.

  3. Si desea descargar un modelo , asegúrese de agregar Firebase a su proyecto de Android , si aún no lo ha hecho. Esto no es necesario cuando empaqueta el modelo.

1. Cargue el modelo

Configurar una fuente de modelo local

Para agrupar el modelo con su aplicación:

  1. Extraiga el modelo y sus metadatos del archivo zip que descargó de la consola Firebase en una carpeta:

    your_model_directory
      |____dict.txt
      |____manifest.json
      |____model.tflite
    

    Los tres archivos deben estar en la misma carpeta. Le recomendamos que utilice los archivos tal como los descargó, sin modificaciones (incluidos los nombres de los archivos).

  2. Copie la carpeta a su proyecto Xcode, teniendo cuidado de seleccionar Crear referencias de carpeta cuando lo haga. El archivo del modelo y los metadatos se incluirán en el paquete de la aplicación y estarán disponibles para ML Kit.

  3. Cree el objeto LocalModel , especificando la ruta al archivo de manifiesto del modelo:

    Rápido

    guard let manifestPath = Bundle.main.path(
        forResource: "manifest",
        ofType: "json",
        inDirectory: "your_model_directory"
    ) else { return true }
    let localModel = LocalModel(manifestPath: manifestPath)
    

    C objetivo

    NSString *manifestPath =
        [NSBundle.mainBundle pathForResource:@"manifest"
                                      ofType:@"json"
                                 inDirectory:@"your_model_directory"];
    MLKLocalModel *localModel =
        [[MLKLocalModel alloc] initWithManifestPath:manifestPath];
    

Configurar una fuente de modelo alojada en Firebase

Para usar el modelo alojado de forma remota, cree un objeto CustomRemoteModel y especifique el nombre que asignó al modelo cuando lo publicó:

Rápido

// Initialize the model source with the name you assigned in
// the Firebase console.
let remoteModelSource = FirebaseModelSource(name: "your_remote_model")
let remoteModel = CustomRemoteModel(remoteModelSource: remoteModelSource)

C objetivo

// Initialize the model source with the name you assigned in
// the Firebase console.
MLKFirebaseModelSource *firebaseModelSource =
    [[MLKFirebaseModelSource alloc] initWithName:@"your_remote_model"];
MLKCustomRemoteModel *remoteModel =
    [[MLKCustomRemoteModel alloc] initWithRemoteModelSource:firebaseModelSource];

Luego, inicie la tarea de descarga del modelo, especificando las condiciones bajo las cuales desea permitir la descarga. Si el modelo no está en el dispositivo, o si hay disponible una versión más reciente del modelo, la tarea descargará el modelo de forma asíncrona desde Firebase:

Rápido

let downloadConditions = ModelDownloadConditions(
  allowsCellularAccess: true,
  allowsBackgroundDownloading: true
)

let downloadProgress = ModelManager.modelManager().download(
  remoteModel,
  conditions: downloadConditions
)

C objetivo

MLKModelDownloadConditions *downloadConditions =
    [[MLKModelDownloadConditions alloc] initWithAllowsCellularAccess:YES
                                         allowsBackgroundDownloading:YES];

NSProgress *downloadProgress =
    [[MLKModelManager modelManager] downloadRemoteModel:remoteModel
                                             conditions:downloadConditions];

Muchas aplicaciones inician la tarea de descarga en su código de inicialización, pero puede hacerlo en cualquier momento antes de que necesite usar el modelo.

Cree un etiquetador de imágenes a partir de su modelo

Después de configurar las fuentes de su modelo, cree un objeto ImageLabeler a partir de una de ellas.

Si solo tiene un modelo empaquetado localmente, simplemente cree un etiquetador a partir de su objeto LocalModel y configure el umbral de puntuación de confianza que desea solicitar (consulte Evaluar su modelo ):

Rápido

let options = CustomImageLabelerOptions(localModel: localModel)
options.confidenceThreshold = NSNumber(value: 0.0)  // Evaluate your model in the Cloud console
                                                    // to determine an appropriate value.
let imageLabeler = ImageLabeler.imageLabeler(options)

C objetivo

CustomImageLabelerOptions *options =
    [[CustomImageLabelerOptions alloc] initWithLocalModel:localModel];
options.confidenceThreshold = @(0.0f);  // Evaluate your model in the Cloud console
                                        // to determine an appropriate value.
MLKImageLabeler *imageLabeler =
    [MLKImageLabeler imageLabelerWithOptions:options];

Si tiene un modelo alojado de forma remota, deberá verificar que se haya descargado antes de ejecutarlo. Puede comprobar el estado de la tarea de descarga del modelo mediante el método isModelDownloaded(remoteModel:) del administrador de modelos.

Aunque solo tiene que confirmar esto antes de ejecutar el etiquetador, si tiene un modelo alojado de forma remota y un modelo empaquetado localmente, podría tener sentido realizar esta verificación al crear una instancia de ImageLabeler : cree un etiquetador desde el modelo remoto si es sido descargado, y del modelo local en caso contrario.

Rápido

var options: CustomImageLabelerOptions
if (ModelManager.modelManager().isModelDownloaded(remoteModel)) {
  options = CustomImageLabelerOptions(remoteModel: remoteModel)
} else {
  options = CustomImageLabelerOptions(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)

C objetivo

MLKCustomImageLabelerOptions *options;
if ([[MLKModelManager modelManager] isModelDownloaded:remoteModel]) {
  options = [[MLKCustomImageLabelerOptions alloc] initWithRemoteModel:remoteModel];
} else {
  options = [[MLKCustomImageLabelerOptions alloc] initWithLocalModel:localModel];
}
options.confidenceThreshold = @(0.0f);  // Evaluate your model in the Firebase console
                                        // to determine an appropriate value.
MLKImageLabeler *imageLabeler =
    [MLKImageLabeler imageLabelerWithOptions:options];

Si solo tiene un modelo alojado de forma remota, debe deshabilitar la funcionalidad relacionada con el modelo, por ejemplo, atenuar u ocultar parte de su interfaz de usuario, hasta que confirme que el modelo se ha descargado.

Puede obtener el estado de descarga del modelo adjuntando observadores al Centro de notificaciones predeterminado. Asegúrese de usar una referencia débil a self en el bloque del observador, ya que las descargas pueden llevar algún tiempo y el objeto de origen puede liberarse cuando finaliza la descarga. Por ejemplo:

Rápido

NotificationCenter.default.addObserver(
    forName: .mlkitMLModelDownloadDidSucceed,
    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: .mlkitMLModelDownloadDidFail,
    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]
    // ...
}

C objetivo

__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. Prepara la imagen de entrada

Cree un objeto VisionImage usando UIImage o CMSampleBufferRef .

Si usa una UIImage , siga estos pasos:

  • Cree un objeto VisionImage con UIImage . Asegúrese de especificar la .orientation correcta.

    Rápido

    let image = VisionImage(image: uiImage)
    visionImage.orientation = image.imageOrientation

    C objetivo

    MLKVisionImage *visionImage = [[MLKVisionImage alloc] initWithImage:image];
    visionImage.orientation = image.imageOrientation;

Si usa un CMSampleBufferRef , siga estos pasos:

  • Especifique la orientación de los datos de imagen contenidos en el búfer CMSampleBufferRef .

    Para obtener la orientación de la imagen:

    Rápido

    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
      }
    }
          

    C objetivo

    - (UIImageOrientation)
      imageOrientationFromDeviceOrientation:(UIDeviceOrientation)deviceOrientation
                             cameraPosition:(AVCaptureDevicePosition)cameraPosition {
      switch (deviceOrientation) {
        case UIDeviceOrientationPortrait:
          return position == AVCaptureDevicePositionFront ? UIImageOrientationLeftMirrored
                                                          : UIImageOrientationRight;
    
        case UIDeviceOrientationLandscapeLeft:
          return position == AVCaptureDevicePositionFront ? UIImageOrientationDownMirrored
                                                          : UIImageOrientationUp;
        case UIDeviceOrientationPortraitUpsideDown:
          return position == AVCaptureDevicePositionFront ? UIImageOrientationRightMirrored
                                                          : UIImageOrientationLeft;
        case UIDeviceOrientationLandscapeRight:
          return position == AVCaptureDevicePositionFront ? UIImageOrientationUpMirrored
                                                          : UIImageOrientationDown;
        case UIDeviceOrientationUnknown:
        case UIDeviceOrientationFaceUp:
        case UIDeviceOrientationFaceDown:
          return UIImageOrientationUp;
      }
    }
          
  • Cree un objeto VisionImage utilizando el objeto CMSampleBufferRef y la orientación:

    Rápido

    let image = VisionImage(buffer: sampleBuffer)
    image.orientation = imageOrientation(
      deviceOrientation: UIDevice.current.orientation,
      cameraPosition: cameraPosition)

    C objetivo

     MLKVisionImage *image = [[MLKVisionImage alloc] initWithBuffer:sampleBuffer];
     image.orientation =
       [self imageOrientationFromDeviceOrientation:UIDevice.currentDevice.orientation
                                    cameraPosition:cameraPosition];

3. Ejecute el etiquetador de imágenes

Asíncronamente:

Rápido

imageLabeler.process(image) { labels, error in
    guard error == nil, let labels = labels, !labels.isEmpty else {
        // Handle the error.
        return
    }
    // Show results.
}

C objetivo

[imageLabeler
    processImage:image
      completion:^(NSArray<MLKImageLabel *> *_Nullable labels,
                   NSError *_Nullable error) {
        if (label.count == 0) {
            // Handle the error.
            return;
        }
        // Show results.
     }];

Sincrónicamente:

Rápido

var labels: [ImageLabel]
do {
    labels = try imageLabeler.results(in: image)
} catch let error {
    // Handle the error.
    return
}
// Show results.

C objetivo

NSError *error;
NSArray<MLKImageLabel *> *labels =
    [imageLabeler resultsInImage:image error:&error];
// Show results or handle the error.

4. Obtener información sobre objetos etiquetados

Si la operación de etiquetado de imágenes tiene éxito, devuelve una matriz de ImageLabel . Cada ImageLabel representa algo que fue etiquetado en la imagen. Puede obtener la descripción de texto de cada etiqueta (si está disponible en los metadatos del archivo del modelo de TensorFlow Lite), la puntuación de confianza y el índice. Por ejemplo:

Rápido

for label in labels {
  let labelText = label.text
  let confidence = label.confidence
  let index = label.index
}

C objetivo

for (MLKImageLabel *label in labels) {
  NSString *labelText = label.text;
  float confidence = label.confidence;
  NSInteger index = label.index;
}

Sugerencias para mejorar el rendimiento en tiempo real

Si desea etiquetar imágenes en una aplicación en tiempo real, siga estas pautas para lograr las mejores tasas de cuadros:

  • Llamadas del acelerador al detector. Si un nuevo cuadro de video está disponible mientras el detector está funcionando, suelte el cuadro.
  • Si está utilizando la salida del detector para superponer gráficos en la imagen de entrada, primero obtenga el resultado, luego renderice la imagen y superponga en un solo paso. Al hacerlo, renderiza en la superficie de visualización solo una vez para cada cuadro de entrada. Consulte las clases previewOverlayView y FIRDetectionOverlayView en la aplicación de ejemplo de presentación para ver un ejemplo.