Erkennen und verfolgen Sie Objekte mit ML Kit auf iOS

Mit dem ML Kit können Sie Objekte über Videobilder hinweg erkennen und verfolgen.

Wenn Sie ML Kit-Bilder übergeben, gibt ML Kit für jedes Bild eine Liste mit bis zu fünf erkannten Objekten und deren Position im Bild zurück. Bei der Erkennung von Objekten in Videostreams verfügt jedes Objekt über eine ID, mit der Sie das Objekt bildübergreifend verfolgen können. Optional können Sie auch die grobe Objektklassifizierung aktivieren, die Objekte mit breiten Kategoriebeschreibungen kennzeichnet.

Bevor Sie beginnen

  1. Wenn Sie Firebase noch nicht zu Ihrer App hinzugefügt haben, befolgen Sie dazu die Schritte im Leitfaden „Erste Schritte“ .
  2. Fügen Sie die ML-Kit-Bibliotheken in Ihre Pod-Datei ein:
    pod 'Firebase/MLVision', '6.25.0'
    pod 'Firebase/MLVisionObjectDetection', '6.25.0'
    
    Nachdem Sie die Pods Ihres Projekts installiert oder aktualisiert haben, stellen Sie sicher, dass Sie Ihr Xcode-Projekt mit seinem .xcworkspace öffnen.
  3. Importieren Sie Firebase in Ihre App:

    Schnell

    import Firebase

    Ziel c

    @import Firebase;

1. Konfigurieren Sie den Objektdetektor

Um mit der Erkennung und Verfolgung von Objekten zu beginnen, erstellen Sie zunächst eine Instanz von VisionObjectDetector und geben Sie optional alle Detektoreinstellungen an, die Sie gegenüber den Standardeinstellungen ändern möchten.

  1. Konfigurieren Sie den Objektdetektor für Ihren Anwendungsfall mit einem VisionObjectDetectorOptions Objekt. Sie können die folgenden Einstellungen ändern:

    Objektdetektoreinstellungen
    Erkennungsmodus .stream (Standard) | .singleImage

    Im Stream-Modus (Standard) läuft der Objektdetektor mit sehr geringer Latenz, kann jedoch bei den ersten Aufrufen des Detektors unvollständige Ergebnisse liefern (z. B. nicht spezifizierte Begrenzungsrahmen oder Kategorien). Außerdem weist der Detektor im Stream-Modus den Objekten Tracking-IDs zu, mit denen Sie Objekte über Frames hinweg verfolgen können. Verwenden Sie diesen Modus, wenn Sie Objekte verfolgen möchten oder wenn eine geringe Latenz wichtig ist, beispielsweise bei der Verarbeitung von Videostreams in Echtzeit.

    Im Einzelbildmodus wartet der Objektdetektor, bis der Begrenzungsrahmen und (sofern Sie die Klassifizierung aktiviert haben) die Kategorie eines erkannten Objekts verfügbar sind, bevor er ein Ergebnis zurückgibt. Infolgedessen ist die Erkennungslatenz möglicherweise höher. Außerdem werden im Einzelbildmodus keine Tracking-IDs zugewiesen. Verwenden Sie diesen Modus, wenn die Latenz nicht kritisch ist und Sie sich nicht mit Teilergebnissen befassen möchten.

    Erkennen und verfolgen Sie mehrere Objekte false (Standard) | true

    Ob bis zu fünf Objekte oder nur das auffälligste Objekt erkannt und verfolgt werden sollen (Standard).

    Objekte klassifizieren false (Standard) | true

    Ob erkannte Objekte in grobe Kategorien eingeteilt werden sollen oder nicht. Wenn der Objektdetektor aktiviert ist, klassifiziert er Objekte in die folgenden Kategorien: Modeartikel, Lebensmittel, Haushaltswaren, Orte, Pflanzen und Unbekannt.

    Die API zur Objekterkennung und -verfolgung ist für diese beiden Kernanwendungsfälle optimiert:

    • Live-Erkennung und Verfolgung des markantesten Objekts im Kamerasucher
    • Erkennung mehrerer Objekte in einem statischen Bild

    So konfigurieren Sie die API für diese Anwendungsfälle:

    Schnell

    // Live detection and tracking
    let options = VisionObjectDetectorOptions()
    options.detectorMode = .stream
    options.shouldEnableMultipleObjects = false
    options.shouldEnableClassification = true  // Optional
    
    // Multiple object detection in static images
    let options = VisionObjectDetectorOptions()
    options.detectorMode = .singleImage
    options.shouldEnableMultipleObjects = true
    options.shouldEnableClassification = true  // Optional
    

    Ziel c

    // Live detection and tracking
    FIRVisionObjectDetectorOptions *options = [[FIRVisionObjectDetectorOptions alloc] init];
    options.detectorMode = FIRVisionObjectDetectorModeStream;
    options.shouldEnableMultipleObjects = NO;
    options.shouldEnableClassification = YES;  // Optional
    
    // Multiple object detection in static images
    FIRVisionObjectDetectorOptions *options = [[FIRVisionObjectDetectorOptions alloc] init];
    options.detectorMode = FIRVisionObjectDetectorModeSingleImage;
    options.shouldEnableMultipleObjects = YES;
    options.shouldEnableClassification = YES;  // Optional
    
  2. Holen Sie sich eine Instanz von FirebaseVisionObjectDetector :

    Schnell

    let objectDetector = Vision.vision().objectDetector()
    
    // Or, to change the default settings:
    let objectDetector = Vision.vision().objectDetector(options: options)
    

    Ziel c

    FIRVisionObjectDetector *objectDetector = [[FIRVision vision] objectDetector];
    
    // Or, to change the default settings:
    FIRVisionObjectDetector *objectDetector = [[FIRVision vision] objectDetectorWithOptions:options];
    

2. Führen Sie den Objektdetektor aus

Um Objekte zu erkennen und zu verfolgen, gehen Sie für jedes Bild oder Videobild wie folgt vor. Wenn Sie den Stream-Modus aktiviert haben, müssen Sie VisionImage Objekte aus CMSampleBufferRef s erstellen.

  1. Erstellen Sie ein VisionImage Objekt mit einem UIImage oder einem CMSampleBufferRef .

    So verwenden Sie ein UIImage :

    1. Drehen Sie das Bild bei Bedarf so, dass seine imageOrientation Eigenschaft .up hat.
    2. Erstellen Sie ein VisionImage Objekt mit dem korrekt gedrehten UIImage . Geben Sie keine Rotationsmetadaten an – der Standardwert .topLeft muss verwendet werden.

      Schnell

      let image = VisionImage(image: uiImage)

      Ziel c

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

    So verwenden Sie ein CMSampleBufferRef :

    1. Erstellen Sie ein VisionImageMetadata Objekt, das die Ausrichtung der im CMSampleBufferRef Puffer enthaltenen Bilddaten angibt.

      So erhalten Sie die Bildausrichtung:

      Schnell

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

      Ziel c

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

      Erstellen Sie dann das Metadatenobjekt:

      Schnell

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

      Ziel c

      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. Erstellen Sie ein VisionImage Objekt mit dem CMSampleBufferRef -Objekt und den Rotationsmetadaten:

      Schnell

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

      Ziel c

      FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer];
      image.metadata = metadata;
  2. Übergeben Sie das VisionImage an eine der Bildverarbeitungsmethoden des Objektdetektors. Sie können entweder die asynchrone Methode process(image:) oder die synchrone Methode results() verwenden.

    So erkennen Sie Objekte asynchron:

    Schnell

    objectDetector.process(image) { detectedObjects, error in
      guard error == nil else {
        // Error.
        return
      }
      guard let detectedObjects = detectedObjects, !detectedObjects.isEmpty else {
        // No objects detected.
        return
      }
    
      // Success. Get object info here.
      // ...
    }
    

    Ziel c

    [objectDetector processImage:image
                      completion:^(NSArray<FIRVisionObject *> * _Nullable objects,
                                   NSError * _Nullable error) {
                        if (error == nil) {
                          return;
                        }
                        if (objects == nil | objects.count == 0) {
                          // No objects detected.
                          return;
                        }
    
                        // Success. Get object info here.
                        // ...
                      }];
    

    So erkennen Sie Objekte synchron:

    Schnell

    var results: [VisionObject]? = nil
    do {
      results = try objectDetector.results(in: image)
    } catch let error {
      print("Failed to detect object with error: \(error.localizedDescription).")
      return
    }
    guard let detectedObjects = results, !detectedObjects.isEmpty else {
      print("Object detector returned no results.")
      return
    }
    
    // ...
    

    Ziel c

    NSError *error;
    NSArray<FIRVisionObject *> *objects = [objectDetector resultsInImage:image
                                                                   error:&error];
    if (error == nil) {
      return;
    }
    if (objects == nil | objects.count == 0) {
      // No objects detected.
      return;
    }
    
    // Success. Get object info here.
    // ...
    
  3. Wenn der Aufruf des Bildprozessors erfolgreich ist, übergibt er entweder eine Liste von VisionObject s an den Completion-Handler oder gibt die Liste zurück, je nachdem, ob Sie die asynchrone oder synchrone Methode aufgerufen haben.

    Jedes VisionObject enthält die folgenden Eigenschaften:

    frame Ein CGRect , das die Position des Objekts im Bild angibt.
    trackingID Eine Ganzzahl, die das Objekt bildübergreifend identifiziert. Nichts im Einzelbildmodus.
    classificationCategory Die grobe Kategorie des Objekts. Wenn für den Objektdetektor keine Klassifizierung aktiviert ist, ist dies immer .unknown .
    confidence Der Konfidenzwert der Objektklassifizierung. Wenn für den Objektdetektor keine Klassifizierung aktiviert ist oder das Objekt als unbekannt klassifiziert ist, ist dies nil .

    Schnell

    // detectedObjects contains one item if multiple object detection wasn't enabled.
    for obj in detectedObjects {
      let bounds = obj.frame
      let id = obj.trackingID
    
      // If classification was enabled:
      let category = obj.classificationCategory
      let confidence = obj.confidence
    }
    

    Ziel c

    // The list of detected objects contains one item if multiple
    // object detection wasn't enabled.
    for (FIRVisionObject *obj in objects) {
      CGRect bounds = obj.frame;
      if (obj.trackingID) {
        NSInteger id = obj.trackingID.integerValue;
      }
    
      // If classification was enabled:
      FIRVisionObjectCategory category = obj.classificationCategory;
      float confidence = obj.confidence.floatValue;
    }
    

Verbesserung der Benutzerfreundlichkeit und Leistung

Um die beste Benutzererfahrung zu erzielen, befolgen Sie diese Richtlinien in Ihrer App:

  • Eine erfolgreiche Objekterkennung hängt von der visuellen Komplexität des Objekts ab. Objekte mit wenigen visuellen Merkmalen müssen möglicherweise einen größeren Teil des Bildes einnehmen, um erkannt zu werden. Sie sollten Benutzern Anleitungen zum Erfassen von Eingaben geben, die gut mit der Art von Objekten funktionieren, die Sie erkennen möchten.
  • Wenn Sie bei der Klassifizierung Objekte erkennen möchten, die nicht eindeutig in die unterstützten Kategorien fallen, implementieren Sie eine spezielle Behandlung für unbekannte Objekte.

Schauen Sie sich auch die [ML Kit Material Design Showcase-App][showcase-link]{: .external } und die Sammlung von Material Design Patterns für maschinelles Lernen an.

Wenn Sie den Streaming-Modus in einer Echtzeitanwendung verwenden, befolgen Sie diese Richtlinien, um die besten Frameraten zu erzielen:

  • Verwenden Sie im Streaming-Modus nicht die Erkennung mehrerer Objekte, da die meisten Geräte keine ausreichenden Bildraten erzeugen können.

  • Deaktivieren Sie die Klassifizierung, wenn Sie sie nicht benötigen.

  • Gasrufe an den Detektor. Wenn ein neues Videobild verfügbar wird, während der Detektor läuft, löschen Sie das Bild.
  • Wenn Sie die Ausgabe des Detektors verwenden, um Grafiken auf dem Eingabebild zu überlagern, rufen Sie zunächst das Ergebnis vom ML Kit ab und rendern Sie dann das Bild und überlagern Sie es in einem einzigen Schritt. Auf diese Weise rendern Sie für jeden Eingaberahmen nur einmal auf der Anzeigeoberfläche. Ein Beispiel finden Sie in den Klassen „previewOverlayView“ und „FIRDetectionOverlayView“ in der Showcase-Beispiel-App.