Objekte mit ML Kit für iOS erkennen und verfolgen

Mit ML Kit können Sie Objekte in aufeinanderfolgenden Videoframes erkennen und verfolgen.

Wenn Sie ein Bild an ML Kit übergeben, werden bis zu fünf Objekte im Bild zusammen mit der Position jedes Objekts im Bild erkannt. Bei der Objekterkennung in Videostreams hat jedes Objekt eine eindeutige ID, mit der Sie das Objekt von Frame zu Frame verfolgen können. Sie können auch die grobe Objektklassifizierung aktivieren, die Objekte mit allgemeinen Kategoriebeschreibungen kennzeichnet.

Ausprobieren

Hinweis

  1. Nehmen Sie die folgenden ML Kit-Pods in Ihre Podfile-Datei auf:
    pod 'GoogleMLKit/ObjectDetection', '3.2.0'
    
  2. Nachdem Sie die Pods Ihres Projekts installiert oder aktualisiert haben, öffnen Sie Ihr Xcode-Projekt mit der zugehörigen .xcworkspace. ML Kit wird in Xcode ab Version 12.4 unterstützt.

1. Objektdetektor konfigurieren

Erstellen Sie zuerst eine Instanz von ObjectDetector und geben Sie optional alle Detektoreinstellungen an, die Sie von der Standardeinstellung ändern möchten, um Objekte zu erkennen und zu verfolgen.

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

    Einstellungen für Objektdetektor
    Erkennungsmodus .stream (Standard) | .singleImage

    Im Streammodus (Standardeinstellung) wird der Objektdetektor mit sehr niedriger Latenz ausgeführt. Bei den ersten Aufrufen des Detektors kann es jedoch zu unvollständigen Ergebnissen (z. B. nicht näher spezifizierte Begrenzungsrahmen oder Kategorien) kommen. Im Streammodus weist der Detektor außerdem Tracking-IDs zu Objekten zu, mit denen Sie Objekte über verschiedene Frames hinweg verfolgen können. Verwenden Sie diesen Modus, wenn Sie Objekte verfolgen möchten oder eine niedrige Latenz wichtig ist, z. B. bei der Verarbeitung von Videostreams in Echtzeit.

    Im Einzelbildmodus gibt der Objektdetektor das Ergebnis zurück, nachdem der Begrenzungsrahmen des Objekts ermittelt wurde. Wenn Sie auch die Klassifizierung aktivieren, wird das Ergebnis zurückgegeben, nachdem der Begrenzungsrahmen und das Kategorielabel verfügbar sind. Infolgedessen ist die Latenz bei der Erkennung potenziell 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.

    Mehrere Objekte erkennen und verfolgen false (Standard) | true

    Gibt an, ob bis zu fünf Objekte oder nur das auffälligste Objekt erkannt und verfolgt werden soll (Standardeinstellung).

    Objekte klassifizieren false (Standard) | true

    Gibt an, ob erkannte Objekte grobe Kategorien zugeordnet werden sollen. Wenn der Objektdetektor aktiviert ist, klassifiziert er Objekte in die folgenden Kategorien: Modewaren, Lebensmittel, Haushaltswaren, Orte und Pflanzen.

    Die Objekterkennungs- und -Tracking-API ist für die folgenden beiden Hauptanwendungsfälle optimiert:

    • Live-Erkennung und Nachverfolgung des auffälligsten Objekts im Kamerasucher
    • Erkennung mehrerer Objekte in einem statischen Bild.

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

Swift

// Live detection and tracking
let options = ObjectDetectorOptions()
options.shouldEnableClassification = true

// Multiple object detection in static images
let options = ObjectDetectorOptions()
options.detectorMode = .singleImage
options.shouldEnableMultipleObjects = true
options.shouldEnableClassification = true

Objective-C

// Live detection and tracking
MLKObjectDetectorOptions *options = [[MLKObjectDetectorOptions alloc] init];
options.shouldEnableClassification = YES;

// Multiple object detection in static images
MLKObjectDetectorOptions *options = [[MLKOptions alloc] init];
options.detectorMode = MLKObjectDetectorModeSingleImage;
options.shouldEnableMultipleObjects = YES;
options.shouldEnableClassification = YES;
  1. Rufen Sie eine Instanz von ObjectDetector ab:

Swift

let objectDetector = ObjectDetector.objectDetector()

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

Objective-C

MLKObjectDetector *objectDetector = [MLKObjectDetector objectDetector];

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

2. Eingabebild vorbereiten

Gehen Sie für jedes Bild oder Videoframes folgendermaßen vor, um Objekte zu erkennen und zu verfolgen: Wenn Sie den Streammodus aktiviert haben, müssen Sie VisionImage-Objekte aus CMSampleBuffers erstellen.

Erstellen Sie mit UIImage oder CMSampleBuffer ein VisionImage-Objekt.

Wenn Sie ein UIImage verwenden, gehen Sie so vor:

  • Erstellen Sie mit UIImage ein VisionImage-Objekt. Achten Sie darauf, den richtigen .orientation anzugeben.

    Swift

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

    Objective-C

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

Wenn Sie ein CMSampleBuffer verwenden, gehen Sie so vor:

  • Gibt die Ausrichtung der Bilddaten an, die in CMSampleBuffer enthalten sind.

    So rufen Sie die Bildausrichtung ab:

    Swift

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

    Objective-C

    - (UIImageOrientation)
      imageOrientationFromDeviceOrientation:(UIDeviceOrientation)deviceOrientation
                             cameraPosition:(AVCaptureDevicePosition)cameraPosition {
      switch (deviceOrientation) {
        case UIDeviceOrientationPortrait:
          return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationLeftMirrored
                                                                : UIImageOrientationRight;
    
        case UIDeviceOrientationLandscapeLeft:
          return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationDownMirrored
                                                                : UIImageOrientationUp;
        case UIDeviceOrientationPortraitUpsideDown:
          return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationRightMirrored
                                                                : UIImageOrientationLeft;
        case UIDeviceOrientationLandscapeRight:
          return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationUpMirrored
                                                                : UIImageOrientationDown;
        case UIDeviceOrientationUnknown:
        case UIDeviceOrientationFaceUp:
        case UIDeviceOrientationFaceDown:
          return UIImageOrientationUp;
      }
    }
          
  • Erstelle ein VisionImage-Objekt mit dem Objekt CMSampleBuffer und der Ausrichtung:

    Swift

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

    Objective-C

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

3. Bild verarbeiten

Übergeben Sie 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:

Swift

objectDetector.process(image) { objects, error in
  guard error == nil else {
    // Error.
    return
  }
  guard !objects.isEmpty else {
    // No objects detected.
    return
  }

  // Success. Get object info here.
  // ...
}

Objective-C

[objectDetector processImage:image
                  completion:^(NSArray * _Nullable objects,
                               NSError * _Nullable error) {
                    if (error == nil) {
                      return;
                    }
                    if (objects.count == 0) {
                      // No objects detected.
                      return;
                    }

                    // Success. Get object info here.
                  }];

So erkennen Sie Objekte synchron:

Swift

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

// Success. Get object info here.

Objective-C

NSError *error;
NSArray *objects = [objectDetector resultsInImage:image error:&error];
if (error == nil) {
  return;
}
if (objects.count == 0) {
  // No objects detected.
  return;
}

// Success. Get object info here.

4. Informationen zu erkannten Objekten abrufen

Wenn der Aufruf an den Bildprozessor erfolgreich ist, übergibt dieser entweder eine Liste von Object-Werten an den Abschluss-Handler oder gibt die Liste zurück, je nachdem, ob Sie die asynchrone oder synchrone Methode aufgerufen haben.

Jeder Object enthält die folgenden Attribute:

frame Ein CGRect, das die Position des Objekts im Bild angibt.
trackingID Eine Ganzzahl, die das Objekt in Bildern identifiziert, oder "nil" im Einzelbildmodus.
labels Ein Array mit Labels, die das vom Detektor zurückgegebene Objekt beschreiben. Das Attribut ist leer, wenn die Detektoroption shouldEnableClassification auf false gesetzt ist.

Swift

// objects contains one item if multiple object detection wasn't enabled.
for object in objects {
  let frame = object.frame
  let trackingID = object.trackingID

  // If classification was enabled:
  let description = object.labels.enumerated().map { (index, label) in
    "Label \(index): \(label.text), \(label.confidence)"
    }.joined(separator:"\n")

}

Objective-C

// The list of detected objects contains one item if multiple
// object detection wasn't enabled.
for (MLKObject *object in objects) {
  CGRect frame = object.frame;
  NSNumber *trackingID = object.trackingID;
  for (MLKObjectLabel *label in object.labels) {
    NSString *labelString = [NSString stringWithFormat: @"%@, %f, %lu",
      label.text, label.confidence, (unsigned long)label.index];
    ...
  }
}

Nutzerfreundlichkeit und Leistung verbessern

Beachten Sie für eine optimale Nutzererfahrung die folgenden Richtlinien in Ihrer App:

  • Die erfolgreiche Objekterkennung hängt von der visuellen Komplexität des Objekts ab. Damit Objekte mit wenigen visuellen Merkmalen erkannt werden, müssen sie möglicherweise einen größeren Teil des Bildes einnehmen. Sie sollten Nutzern Hinweise zur Erfassung von Eingaben geben, die gut für die Art von Objekten funktionieren, die Sie erkennen möchten.
  • Wenn Sie bei der Klassifizierung Objekte erkennen möchten, die nicht ordnungsgemäß in die unterstützten Kategorien fallen, implementieren Sie eine spezielle Behandlung für unbekannte Objekte.

Sehen Sie sich auch die Material Design-Sammlung Muster für Funktionen mit maschinellem Lernen an.

Wenn Sie den Streamingmodus in einer Echtzeitanwendung verwenden, beachten Sie die folgenden Richtlinien, um die besten Framerates zu erzielen:

  • Verwende im Streamingmodus nicht die Erkennung mehrerer Objekte, da die meisten Geräte keine angemessenen Framerates produzieren können.
  • Deaktivieren Sie die Klassifizierung, wenn Sie sie nicht benötigen.
  • Verwenden Sie zum Verarbeiten von Videobildern die synchrone results(in:)-API des Detektors. Rufen Sie diese Methode über die captureOutput(_, didOutput:from:)-Funktion von AVCaptureVideoDataOutputSampleBufferDelegate auf, um synchron Ergebnisse aus dem angegebenen Videoframe zu erhalten. Behalten Sie die alwaysDiscardsLateVideoFrames von AVCaptureVideoDataOutput als true bei, um Aufrufe an den Detektor zu drosseln. Wenn ein neuer Videoframe verfügbar wird, während der Detektor ausgeführt wird, wird er gelöscht.
  • Wenn Sie die Ausgabe des Detektors verwenden, um Grafiken über das Eingabebild einzublenden, rufen Sie zuerst das Ergebnis aus ML Kit ab und rendern Sie dann das Bild und Overlay in einem einzigen Schritt. Dadurch wird für jeden verarbeiteten Eingabeframe nur einmal ein Rendering auf der Anzeigeoberfläche ausgeführt. Ein Beispiel finden Sie unter updatePreviewOverlayViewWithLastFrame im ML Kit-Schnellstartbeispiel.