了解 2023 年 Google I/O 大会上介绍的 Firebase 亮点。了解详情

Erkennen und verfolgen Sie Objekte mit ML Kit unter iOS

Sie können ML Kit verwenden, um Objekte über Videoframes hinweg zu erkennen und zu 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. Beim Erkennen von Objekten in Videostreams hat jedes Objekt eine ID, mit der Sie das Objekt über Bilder hinweg verfolgen können. Sie können optional auch die grobe Objektklassifizierung aktivieren, die Objekte mit breiten Kategoriebeschreibungen kennzeichnet.

Bevor Sie beginnen

  1. Wenn Sie Ihrer App Firebase noch nicht hinzugefügt haben, befolgen Sie dazu die Schritte im Leitfaden „Erste Schritte“ .
  2. Schließen Sie die ML Kit-Bibliotheken in Ihre Poddatei ein:
    pod 'Firebase/MLVision', '6.25.0'
    pod 'Firebase/MLVisionObjectDetection', '6.25.0'
    
    Nachdem Sie die Pods Ihres Projekts installiert oder aktualisiert haben, müssen Sie Ihr Xcode-Projekt mit seiner .xcworkspace .
  3. Importieren Sie in Ihrer App Firebase:

    Schnell

    import Firebase

    Ziel c

    @import Firebase;

1. Konfigurieren Sie den Objektdetektor

Um mit dem Erkennen und Verfolgen von Objekten zu beginnen, erstellen Sie zunächst eine Instanz von VisionObjectDetector , und geben Sie optional alle Detektoreinstellungen an, die Sie von der Standardeinstellung ändern möchten.

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

    Objektdetektor-Einstellungen
    Erkennungsmodus .stream (Standard) | .singleImage

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

    Im Einzelbildmodus wartet der Objektdetektor, bis der Begrenzungsrahmen eines erkannten Objekts und (falls Sie die Klassifizierung aktiviert haben) die Kategorie verfügbar sind, bevor er ein Ergebnis zurückgibt. Folglich 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 nicht mit Teilergebnissen arbeiten möchten.

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

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

    Objekte klassifizieren false (Standard) | true

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

    Die Objekterkennungs- und Tracking-API 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. Rufen Sie 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 Videoeinzelbild 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 Eigenschaft imageOrientation .up .
    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 eine 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 process(image:) Methode oder die synchrone results() Methode 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.
                        // ...
                      }];
    

    Objekte synchron erkennen:

    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 Abschlusshandler oder gibt die Liste zurück, je nachdem, ob Sie die asynchrone oder die synchrone Methode aufgerufen haben.

    Jedes VisionObject enthält die folgenden Eigenschaften:

    frame Ein CGRect , der die Position des Objekts im Bild angibt.
    trackingID Eine ganze Zahl, die das Objekt bildübergreifend identifiziert. Null im Einzelbildmodus.
    classificationCategory Die grobe Kategorie des Objekts. Wenn der Objektdetektor keine Klassifizierung aktiviert hat, ist dies immer .unknown .
    confidence Der Konfidenzwert der Objektklassifikation. Wenn der Objektdetektor keine Klassifizierung aktiviert hat 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

Befolgen Sie für die beste Benutzererfahrung 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 zu erkennenden Bildes einnehmen. Sie sollten den Benutzern Anleitungen zum Erfassen von Eingaben geben, die gut mit der Art von Objekten funktionieren, die Sie erkennen möchten.
  • Wenn Sie bei Verwendung der Klassifizierung Objekte erkennen möchten, die nicht eindeutig in die unterstützten Kategorien fallen, implementieren Sie eine spezielle Behandlung für unbekannte Objekte.

Sehen Sie sich auch die [ML Kit Material Design Showcase App][showcase-link]{: .external } und die Material Design Patterns for Machine Learning-gestützte Funktionssammlung 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 keine Mehrfachobjekterkennung, da die meisten Geräte keine angemessenen Frameraten erzeugen können.

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

  • Drosselrufe an den Detektor. Wenn ein neuer Videoframe verfügbar wird, während der Detektor läuft, löschen Sie den Frame.
  • Wenn Sie die Ausgabe des Detektors verwenden, um Grafiken auf das Eingabebild zu legen, rufen Sie zuerst das Ergebnis von ML Kit ab, rendern Sie dann das Bild und überlagern Sie es in einem einzigen Schritt. Dadurch rendern Sie für jeden Eingabeframe nur einmal auf der Anzeigeoberfläche. Ein Beispiel finden Sie in den Klassen previewOverlayView und FIRDetectionOverlayView in der Showcase-Beispiel-App.