Etiquetar imágenes con un modelo entrenado en AutoML en plataformas Apple

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

Hay dos formas de integrar modelos entrenados desde AutoML Vision Edge. Puedes agrupar el modelo copiando los archivos del modelo en tu proyecto Xcode, o puedes 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 inmediatamente, incluso cuando el dispositivo Apple está desconectado
  • 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.
  • Actualizaciones de modelos push sin volver a publicar su aplicación
  • Pruebas A/B sencillas con Firebase Remote Config
  • Requiere un proyecto de Firebase

Antes de que empieces

  1. Incluya las bibliotecas del kit ML en su Podfile:

    Para agrupar un modelo con su aplicación:

    pod 'GoogleMLKit/ImageLabelingCustom'
    

    Para descargar dinámicamente un modelo desde Firebase, agregue la dependencia 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 agrupa 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 Firebase console 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 de 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 utilizar el modelo alojado de forma remota, cree un objeto CustomRemoteModel , especificando el nombre que le 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 una versión más reciente del modelo disponible, la tarea descargará el modelo de forma asincrónica 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 necesitar usar el modelo.

Crea un etiquetador de imágenes a partir de tu 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á comprobar que se haya descargado antes de ejecutarlo. Puede verificar el estado de la tarea de descarga del modelo utilizando 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 a partir del modelo remoto si es 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 desactivar 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 utilizar una referencia débil a self en el bloque de observador, ya que las descargas pueden tardar 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. Prepare la imagen de entrada

Cree un objeto VisionImage utilizando UIImage o CMSampleBufferRef .

Si utiliza 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 utiliza CMSampleBufferRef , siga estos pasos:

  • Especifique la orientación de los datos de la 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)

    Objetivo-C

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

3. Ejecute el etiquetador de imágenes.

Asincrónicamente:

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

Consejos 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 velocidades de fotogramas:

  • Llamadas del acelerador al detector. Si hay un nuevo cuadro de video disponible mientras el detector está en ejecución, 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 superpóngala en un solo paso. Al hacerlo, renderiza en la superficie de visualización solo una vez por cada cuadro de entrada. Consulte las clases previaOverlayView y FIRDetectionOverlayView en la aplicación de muestra de presentación para ver un ejemplo.