Etiquetar imágenes con un modelo entrenado en AutoML en iOS

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

Antes de que empieces

  1. Si aún no has agregado Firebase a tu aplicación, hazlo siguiendo los pasos de la guía de introducción .
  2. Incluya las bibliotecas del kit ML en su Podfile:
    pod 'Firebase/MLVision', '6.25.0'
    pod 'Firebase/MLVisionAutoML', '6.25.0'
    
    Después de instalar o actualizar los Pods de su proyecto, asegúrese de abrir su proyecto Xcode usando su .xcworkspace .
  3. En tu aplicación, importa Firebase:

    Rápido

    import Firebase

    C objetivo

    @import Firebase;

1. Cargue el modelo

ML Kit ejecuta sus modelos generados por AutoML en el dispositivo. Sin embargo, puedes configurar ML Kit para cargar tu modelo de forma remota desde Firebase, desde el almacenamiento local o ambos.

Al alojar el modelo en Firebase, puedes actualizarlo sin lanzar una nueva versión de la aplicación, y puedes usar Remote Config y A/B Testing para servir dinámicamente diferentes modelos a diferentes conjuntos de usuarios.

Si elige proporcionar el modelo únicamente alojándolo en Firebase y no incluirlo con su aplicación, puede reducir el tamaño de descarga inicial de su aplicación. Sin embargo, tenga en cuenta que si el modelo no está incluido con su aplicación, cualquier funcionalidad relacionada con el modelo no estará disponible hasta que su aplicación descargue el modelo por primera vez.

Al combinar tu modelo con tu aplicación, puedes asegurarte de que las funciones de aprendizaje automático de tu aplicación sigan funcionando cuando el modelo alojado en Firebase no esté disponible.

Configurar una fuente de modelo alojada en Firebase

Para utilizar el modelo alojado de forma remota, cree un objeto AutoMLRemoteModel , especificando el nombre que le asignó al modelo cuando lo publicó:

Rápido

let remoteModel = AutoMLRemoteModel(
    name: "your_remote_model"  // The name you assigned in the Firebase console.
)

C objetivo

FIRAutoMLRemoteModel *remoteModel = [[FIRAutoMLRemoteModel alloc]
    initWithName:@"your_remote_model"];  // The name you assigned in the Firebase console.

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

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

NSProgress *downloadProgress =
    [[FIRModelManager 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.

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 un objeto AutoMLLocalModel , 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 = AutoMLLocalModel(manifestPath: manifestPath)
    

    C objetivo

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

Crea un etiquetador de imágenes a partir de tu modelo.

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

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

Rápido

let options = VisionOnDeviceAutoMLImageLabelerOptions(localModel: localModel)
options.confidenceThreshold = 0  // Evaluate your model in the Firebase console
                                 // to determine an appropriate value.
let labeler = Vision.vision().onDeviceAutoMLImageLabeler(options: options)

C objetivo

FIRVisionOnDeviceAutoMLImageLabelerOptions *options =
    [[FIRVisionOnDeviceAutoMLImageLabelerOptions alloc] initWithLocalModel:localModel];
options.confidenceThreshold = 0;  // Evaluate your model in the Firebase console
                                  // to determine an appropriate value.
FIRVisionImageLabeler *labeler =
    [[FIRVision vision] onDeviceAutoMLImageLabelerWithOptions: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 VisionImageLabeler : cree un etiquetador a partir del modelo remoto si es descargado, y del modelo local en caso contrario.

Rápido

var options: VisionOnDeviceAutoMLImageLabelerOptions?
if (ModelManager.modelManager().isModelDownloaded(remoteModel)) {
  options = VisionOnDeviceAutoMLImageLabelerOptions(remoteModel: remoteModel)
} else {
  options = VisionOnDeviceAutoMLImageLabelerOptions(localModel: localModel)
}
options.confidenceThreshold = 0  // Evaluate your model in the Firebase console
                                 // to determine an appropriate value.
let labeler = Vision.vision().onDeviceAutoMLImageLabeler(options: options)

C objetivo

VisionOnDeviceAutoMLImageLabelerOptions *options;
if ([[FIRModelManager modelManager] isModelDownloaded:remoteModel]) {
  options = [[FIRVisionOnDeviceAutoMLImageLabelerOptions alloc] initWithRemoteModel:remoteModel];
} else {
  options = [[FIRVisionOnDeviceAutoMLImageLabelerOptions alloc] initWithLocalModel:localModel];
}
options.confidenceThreshold = 0.0f;  // Evaluate your model in the Firebase console
                                     // to determine an appropriate value.
FIRVisionImageLabeler *labeler = [[FIRVision vision] onDeviceAutoMLImageLabelerWithOptions: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: .firebaseMLModelDownloadDidSucceed,
    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: .firebaseMLModelDownloadDidFail,
    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:FIRModelDownloadDidSucceedNotification
                object:nil
                 queue:nil
            usingBlock:^(NSNotification *_Nonnull note) {
              if (weakSelf == nil | note.userInfo == nil) {
                return;
              }
              __strong typeof(self) strongSelf = weakSelf;

              FIRRemoteModel *model = note.userInfo[FIRModelDownloadUserInfoKeyRemoteModel];
              if ([model.name isEqualToString:@"your_remote_model"]) {
                // The model was downloaded and is available on the device
              }
            }];

[NSNotificationCenter.defaultCenter
    addObserverForName:FIRModelDownloadDidFailNotification
                object:nil
                 queue:nil
            usingBlock:^(NSNotification *_Nonnull note) {
              if (weakSelf == nil | note.userInfo == nil) {
                return;
              }
              __strong typeof(self) strongSelf = weakSelf;

              NSError *error = note.userInfo[FIRModelDownloadUserInfoKeyError];
            }];

2. Prepare la imagen de entrada

Luego, para cada imagen que desee etiquetar, cree un objeto VisionImage usando una de las opciones descritas en esta sección y páselo a una instancia de VisionImageLabeler (descrita en la siguiente sección).

Cree un objeto VisionImage utilizando UIImage o CMSampleBufferRef .

Para usar una UIImage :

  1. Si es necesario, gire la imagen para que su propiedad imageOrientation sea .up .
  2. Cree un objeto VisionImage utilizando UIImage girado correctamente. No especifique ningún metadato de rotación; se debe utilizar el valor predeterminado, .topLeft .

    Rápido

    let image = VisionImage(image: uiImage)

    C objetivo

    FIRVisionImage *image = [[FIRVisionImage alloc] initWithImage:uiImage];

Para utilizar CMSampleBufferRef :

  1. Cree un objeto VisionImageMetadata que 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
        ) -> VisionDetectorImageOrientation {
        switch deviceOrientation {
        case .portrait:
            return cameraPosition == .front ? .leftTop : .rightTop
        case .landscapeLeft:
            return cameraPosition == .front ? .bottomLeft : .topLeft
        case .portraitUpsideDown:
            return cameraPosition == .front ? .rightBottom : .leftBottom
        case .landscapeRight:
            return cameraPosition == .front ? .topRight : .bottomRight
        case .faceDown, .faceUp, .unknown:
            return .leftTop
        }
    }

    C objetivo

    - (FIRVisionDetectorImageOrientation)
        imageOrientationFromDeviceOrientation:(UIDeviceOrientation)deviceOrientation
                               cameraPosition:(AVCaptureDevicePosition)cameraPosition {
      switch (deviceOrientation) {
        case UIDeviceOrientationPortrait:
          if (cameraPosition == AVCaptureDevicePositionFront) {
            return FIRVisionDetectorImageOrientationLeftTop;
          } else {
            return FIRVisionDetectorImageOrientationRightTop;
          }
        case UIDeviceOrientationLandscapeLeft:
          if (cameraPosition == AVCaptureDevicePositionFront) {
            return FIRVisionDetectorImageOrientationBottomLeft;
          } else {
            return FIRVisionDetectorImageOrientationTopLeft;
          }
        case UIDeviceOrientationPortraitUpsideDown:
          if (cameraPosition == AVCaptureDevicePositionFront) {
            return FIRVisionDetectorImageOrientationRightBottom;
          } else {
            return FIRVisionDetectorImageOrientationLeftBottom;
          }
        case UIDeviceOrientationLandscapeRight:
          if (cameraPosition == AVCaptureDevicePositionFront) {
            return FIRVisionDetectorImageOrientationTopRight;
          } else {
            return FIRVisionDetectorImageOrientationBottomRight;
          }
        default:
          return FIRVisionDetectorImageOrientationTopLeft;
      }
    }

    Luego, crea el objeto de metadatos:

    Rápido

    let cameraPosition = AVCaptureDevice.Position.back  // Set to the capture device you used.
    let metadata = VisionImageMetadata()
    metadata.orientation = imageOrientation(
        deviceOrientation: UIDevice.current.orientation,
        cameraPosition: cameraPosition
    )

    C objetivo

    FIRVisionImageMetadata *metadata = [[FIRVisionImageMetadata alloc] init];
    AVCaptureDevicePosition cameraPosition =
        AVCaptureDevicePositionBack;  // Set to the capture device you used.
    metadata.orientation =
        [self imageOrientationFromDeviceOrientation:UIDevice.currentDevice.orientation
                                     cameraPosition:cameraPosition];
  2. Cree un objeto VisionImage utilizando el objeto CMSampleBufferRef y los metadatos de rotación:

    Rápido

    let image = VisionImage(buffer: sampleBuffer)
    image.metadata = metadata

    C objetivo

    FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer];
    image.metadata = metadata;

3. Ejecute el etiquetador de imágenes.

Para etiquetar objetos en una imagen, pase el objeto VisionImage al método process() de VisionImageLabeler :

Rápido

labeler.process(image) { labels, error in
    guard error == nil, let labels = labels else { return }

    // Task succeeded.
    // ...
}

C objetivo

[labeler
    processImage:image
      completion:^(NSArray<FIRVisionImageLabel *> *_Nullable labels, NSError *_Nullable error) {
        if (error != nil || labels == nil) {
          return;
        }

        // Task succeeded.
        // ...
      }];

Si el etiquetado de imágenes se realiza correctamente, se pasará una matriz de objetos VisionImageLabel al controlador de finalización. De cada objeto, puede obtener información sobre una característica reconocida en la imagen.

Por ejemplo:

Rápido

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

C objetivo

for (FIRVisionImageLabel *label in labels) {
  NSString *labelText = label.text;
  NSNumber *confidence = label.confidence;
}

Consejos para mejorar el rendimiento en tiempo real

  • 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 del ML Kit, 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.