Leitfaden zum Einbetten von Bildern für iOS

Mit der MediaPipe-Aufgabe „Image Embedder“ können Sie Bilddaten in eine numerische Darstellung umwandeln, um ML-bezogene Bildverarbeitungsaufgaben auszuführen, z. B. den Vergleich der Ähnlichkeit zweier Bilder.

Der in dieser Anleitung beschriebene Code ist auf GitHub verfügbar. In dieser Webdemo können Sie sich diese Aufgabe in Aktion ansehen. Weitere Informationen zu den Funktionen, Modellen und Konfigurationsoptionen dieser Aufgabe finden Sie in der Übersicht.

Codebeispiel

Der Beispielcode für MediaPipe Tasks ist eine grundlegende Implementierung einer Bild-Embedder-App für iOS. Im Beispiel wird die Kamera eines physischen iOS-Geräts verwendet, um Bilder kontinuierlich einzubetten. Der Embedder kann auch auf Bilddateien aus der Gerätegalerie ausgeführt werden.

Sie können die App als Ausgangspunkt für Ihre eigene iOS-App verwenden oder sich an ihr orientieren, wenn Sie eine vorhandene App ändern. Der Beispielcode für den Image Embedder wird auf GitHub gehostet.

Code herunterladen

In der folgenden Anleitung wird beschrieben, wie Sie mit dem Befehlszeilentool git eine lokale Kopie des Beispielcodes erstellen.

So laden Sie den Beispielcode herunter:

  1. Klonen Sie das Git-Repository mit dem folgenden Befehl:

    git clone https://github.com/google-ai-edge/mediapipe-samples
    
  2. Optional können Sie Ihre Git-Instanz für die Verwendung der dünnbesetzten Bezahlung konfigurieren, damit Sie nur die Dateien für die Beispielanwendung „Image Embedder“ (Bildeinbetter) haben:

    cd mediapipe
    git sparse-checkout init --cone
    git sparse-checkout set examples/image_embedder/ios
    

Nachdem Sie eine lokale Version des Beispielcodes erstellt haben, können Sie die MediaPipe-Aufgabenbibliothek installieren, das Projekt mit Xcode öffnen und die App ausführen. Eine Anleitung finden Sie im Einrichtungsleitfaden für iOS.

Schlüsselkomponenten

Die folgenden Dateien enthalten den wichtigsten Code für die Beispielanwendung „Image Embedder“:

Einrichtung

In diesem Abschnitt werden die wichtigsten Schritte zum Einrichten der Entwicklungsumgebung und Codeprojekte für die Verwendung von Image Embedder beschrieben. Allgemeine Informationen zum Einrichten der Entwicklungsumgebung für die Verwendung von MediaPipe-Aufgaben, einschließlich der Anforderungen an die Plattformversion, finden Sie im Einrichtungsleitfaden für iOS.

Abhängigkeiten

Der Bild-Embedder verwendet die MediaPipeTasksVision-Bibliothek, die mit CocoaPods installiert werden muss. Die Bibliothek ist sowohl mit Swift- als auch mit Objective-C-Apps kompatibel und erfordert keine zusätzliche sprachspezifische Einrichtung.

Eine Anleitung zum Installieren von CocoaPods unter macOS findest du in der Installationsanleitung für CocoaPods. Eine Anleitung zum Erstellen einer Podfile mit den erforderlichen Pods für Ihre App finden Sie unter CocoaPods verwenden.

Fügen Sie den MediaPipeTasksVision-Pod mit dem folgenden Code in den Podfile ein:

target 'MyImageEmbedderApp' do
  use_frameworks!
  pod 'MediaPipeTasksVision'
end

Wenn Ihre App Unit-Testziele enthält, finden Sie im Einrichtungsleitfaden für iOS weitere Informationen zur Einrichtung Ihrer Podfile.

Modell

Für die MediaPipe-Aufgabe „Image Embedder“ ist ein trainiertes Modell erforderlich, das mit dieser Aufgabe kompatibel ist. Weitere Informationen zu den verfügbaren trainierten Modellen für den Bild-Embedder finden Sie im Abschnitt „Modelle“.

Wählen Sie ein Modell aus, laden Sie es herunter und fügen Sie es mit Xcode Ihrem Projektverzeichnis hinzu. Eine Anleitung zum Hinzufügen von Dateien zu Ihrem Xcode-Projekt finden Sie unter Dateien und Ordner in Ihrem Xcode-Projekt verwalten.

Verwenden Sie das Attribut BaseOptions.modelAssetPath, um den Pfad zum Modell in Ihrem App-Bundle anzugeben.

Aufgabe erstellen

Sie können die Aufgabe „Image Embedder“ erstellen, indem Sie einen ihrer Initialisierer aufrufen. Der ImageEmbedder(options:)-Initialisierer akzeptiert Werte für die Konfigurationsoptionen.

Wenn Sie keinen Bildeinbetter benötigen, der mit benutzerdefinierten Konfigurationsoptionen initialisiert wurde, können Sie mit dem ImageEmbedder(modelPath:)-Initialisierer einen Bildeinbetter mit den Standardoptionen erstellen. Weitere Informationen zu Konfigurationsoptionen finden Sie unter Konfigurationsübersicht.

Die Aufgabe „Bild-Embedder“ unterstützt drei Eingabedatentypen: Standbilder, Videodateien und Livestreams. Standardmäßig initialisiert ImageEmbedder(modelPath:) eine Aufgabe für Standbilder. Wenn Sie möchten, dass Ihre Aufgabe für die Verarbeitung von Videodateien oder Live-Videostreams initialisiert wird, geben Sie mit ImageEmbedder(options:) den Ausführungsmodus für Video oder Livestream an. Für den Livestream-Modus ist außerdem die zusätzliche Konfigurationsoption imageEmbedderLiveStreamDelegate erforderlich. Damit kann der Image Embedder die Ergebnisse des Bild-Embeddings asynchron an den delegierten Dienst senden.

Wählen Sie den Tab für den aktuellen Ausführungsmodus aus, um zu erfahren, wie Sie die Aufgabe erstellen und die Inferenz ausführen.

Swift

Bild

import MediaPipeTasksVision

let modelPath = Bundle.main.path(
  forResource: "model",
  ofType: "tflite")

let options = ImageEmbedderOptions()
options.baseOptions.modelAssetPath = modelPath
options.quantize = true
options.l2Normalize = true

let imageEmbedder = try ImageEmbedder(options: options)
    

Video

import MediaPipeTasksVision

let modelPath = Bundle.main.path(
  forResource: "model",
  ofType: "tflite")

let options = ImageEmbedderOptions()
options.baseOptions.modelAssetPath = modelPath
options.runningMode = .video
options.quantize = true
options.l2Normalize = true

let imageEmbedder = try ImageEmbedder(options: options)
    

Livestream

import MediaPipeTasksVision

// Class that conforms to the `ImageEmbedderLiveStreamDelegate` protocol and
// implements the method that the image embedder calls once it finishes
// embedding each input frame.
class ImageEmbedderResultProcessor: NSObject, ImageEmbedderLiveStreamDelegate {

  func imageEmbedder(
    _ imageEmbedder: ImageEmbedder,
    didFinishEmbedding result: ImageEmbedderResult?,
    timestampInMilliseconds: Int,
    error: Error?) {

    // Process the image embedder result or errors here.

  }
}

let modelPath = Bundle.main.path(
  forResource: "model",
  ofType: "tflite")

let options = ImageEmbedderOptions()
options.baseOptions.modelAssetPath = modelPath
options.runningMode = .liveStream
options.quantize = true
options.l2Normalize = true

// Assign an object of the class to the `imageEmbedderLiveStreamDelegate`
// property.
let processor = ImageEmbedderResultProcessor()
options.imageEmbedderLiveStreamDelegate = processor

let imageEmbedder = try ImageEmbedder(options: options)
    

Objective-C

Bild

@import MediaPipeTasksVision;

NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"model"
                                                      ofType:@"tflite"];

MPPImageEmbedderOptions *options = [[MPPImageEmbedderOptions alloc] init];
options.baseOptions.modelAssetPath = modelPath;
options.runningMode = MPPRunningModeImage;
options.quantize = YES;
options.l2Normalize = YES;

MPPImageEmbedder *imageEmbedder =
  [[MPPImageEmbedder alloc] initWithOptions:options error:nil];
    

Video

@import MediaPipeTasksVision;

NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"model"
                                                      ofType:@"tflite"];

MPPImageEmbedderOptions *options = [[MPPImageEmbedderOptions alloc] init];
options.baseOptions.modelAssetPath = modelPath;
options.runningMode = MPPRunningModeVideo;
options.quantize = YES;
options.l2Normalize = YES;

MPPImageEmbedder *imageEmbedder =
  [[MPPImageEmbedder alloc] initWithOptions:options error:nil];
    

Livestream

@import MediaPipeTasksVision;

// Class that conforms to the `MPPImageEmbedderLiveStreamDelegate` protocol
// and implements the method that the image embedder calls once it finishes
// embedding each input frame.
@interface APPImageEmbedderResultProcessor : NSObject 

@end

@implementation APPImageEmbedderResultProcessor

-   (void)imageEmbedder:(MPPImageEmbedder *)imageEmbedder
    didFinishEmbeddingWithResult:(MPPImageEmbedderResult *)imageEmbedderResult
         timestampInMilliseconds:(NSInteger)timestampInMilliseconds
                           error:(NSError *)error {

    // Process the image embedder result or errors here.

}

@end

NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"model"
                                                      ofType:@"tflite"];

MPPImageEmbedderOptions *options = [[MPPImageEmbedderOptions alloc] init];
options.baseOptions.modelAssetPath = modelPath;
options.runningMode = MPPRunningModeLiveStream;
options.quantize = YES;
options.l2Normalize = YES;

// Assign an object of the class to the `imageEmbedderLiveStreamDelegate`
// property.
APPImageEmbedderResultProcessor *processor =
  [APPImageEmbedderResultProcessor new];
options.imageEmbedderLiveStreamDelegate = processor;

MPPImageEmbedder *imageEmbedder =
  [[MPPImageEmbedder alloc] initWithOptions:options error:nil];
    

Konfigurationsoptionen

Für diese Aufgabe stehen die folgenden Konfigurationsoptionen für iOS-Apps zur Verfügung:

Optionsname Beschreibung Wertebereich Standardwert
runningMode Legt den Ausführungsmodus für die Aufgabe fest. Der Bild-Embedder hat drei Modi:

IMAGE: Der Modus für einzelne Bildeingaben.

VIDEO: Der Modus für decodierte Frames eines Videos.

LIVE_STREAM: Der Modus für einen Livestream von Eingabedaten, z. B. von einer Kamera. In diesem Modus muss imageEmbedderLiveStreamDelegate auf eine Instanz einer Klasse festgelegt sein, die ImageEmbedderLiveStreamDelegate implementiert, um die Ergebnisse des asynchronen Einbettens von Bildframes zu erhalten.
{RunningMode.image, RunningMode.video, RunningMode.liveStream} {RunningMode.image}
l2Normalize Gibt an, ob der zurückgegebene Feature-Vektor mit der L2-Norm normalisiert werden soll. Verwenden Sie diese Option nur, wenn das Modell noch keine native TFLite-Operation vom Typ „L2_NORMALIZATION“ enthält. In den meisten Fällen ist das bereits der Fall und die L2-Normalisierung wird daher durch TFLite-Inferenz erreicht, ohne dass diese Option erforderlich ist. Boolescher Wert falsch
quantize Gibt an, ob die zurückgegebene Einbettung über die Skalarquantisierung in Bytes quantisiert werden soll. Für Einbettungen wird implizit davon ausgegangen, dass sie normiert sind. Daher hat jede Dimension garantiert einen Wert im Bereich [−1,0; 1,0]. Verwenden Sie die Option „l2Normalize“, wenn dies nicht der Fall ist. Boolescher Wert falsch

Wenn der Ausführungsmodus auf „Livestream“ festgelegt ist, benötigt der Bild-Embedder die zusätzliche Konfigurationsoption imageEmbedderLiveStreamDelegate. Dadurch kann der Bild-Embedder die Ergebnisse des Bild-Embeddings asynchron liefern. Der Bevollmächtigte muss die Methode imageEmbedder(_:didFinishEmbedding:timestampInMilliseconds:error:) implementieren, die der Bildeinbetter nach Verarbeitung der Ergebnisse der Einbettung jedes Eingabebildframes aufruft.

Optionsname Beschreibung Wertebereich Standardwert
imageEmbedderLiveStreamDelegate Ermöglicht es dem Image Embedder, die Ergebnisse des Einbettens von Bildern asynchron im Livestream-Modus zu erhalten. Die Klasse, deren Instanz auf diese Property festgelegt ist, muss die Methode imageEmbedder(_:didFinishEmbedding:timestampInMilliseconds:error:) implementieren. Nicht zutreffend Nicht festgelegt

Daten vorbereiten

Du musst das Eingabebild oder den Frame in ein MPImage-Objekt konvertieren, bevor du es an den Bild-Embedder weitergibst. MPImage unterstützt verschiedene Arten von iOS-Bildformaten und kann sie in jedem Betriebsmodus für die Inferenz verwenden. Weitere Informationen zu MPImage finden Sie in der MPImage API.

Wählen Sie ein iOS-Bildformat entsprechend Ihrem Anwendungsfall und dem erforderlichen Ausführungsmodus Ihrer Anwendung aus.MPImage unterstützt die iOS-Bildformate UIImage, CVPixelBuffer und CMSampleBuffer.

UIImage

Das Format UIImage eignet sich gut für die folgenden Laufmodi:

  • Bilder: Bilder aus einem App-Bundle, einer Nutzergalerie oder einem Dateisystem, das als UIImage-Bilder formatiert ist, können in ein MPImage-Objekt umgewandelt werden.

  • Videos: Mit dem AVAssetImageGenerator können Sie Videoframes im CGImage-Format extrahieren und dann in UIImage-Bilder konvertieren.

Swift

// Load an image on the user's device as an iOS `UIImage` object.

// Convert the `UIImage` object to a MediaPipe's Image object having the default
// orientation `UIImage.Orientation.up`.
let image = try MPImage(uiImage: image)
    

Objective-C

// Load an image on the user's device as an iOS `UIImage` object.

// Convert the `UIImage` object to a MediaPipe's Image object having the default
// orientation `UIImageOrientationUp`.
MPImage *image = [[MPPImage alloc] initWithUIImage:image error:nil];
    

Im Beispiel wird eine MPImage mit der Standardausrichtung UIImage.Orientation.Up initialisiert. Sie können MPImage mit jedem der unterstützten Werte für UIImage.Orientation initialisieren. Der Bildeinbetter unterstützt keine gespiegelten Ausrichtungen wie .upMirrored, .downMirrored, .leftMirrored und .rightMirrored.

Weitere Informationen zu UIImage finden Sie in der Apple Developer-Dokumentation zu UIImage.

CVPixelBuffer

Das CVPixelBuffer-Format eignet sich gut für Anwendungen, die Frames generieren und das iOS-CoreImage-Framework für die Verarbeitung verwenden.

Das CVPixelBuffer-Format eignet sich gut für die folgenden Laufmodi:

  • Bilder: Apps, die nach einer Verarbeitung mit dem CoreImage-Framework von iOS CVPixelBuffer-Bilder generieren, können im Bildausführungsmodus an den Bildeinbetter gesendet werden.

  • Videos: Videoframes können zur Verarbeitung in das CVPixelBuffer-Format konvertiert und dann im Videomodus an den Image Embedder gesendet werden.

  • Livestream: Apps, die eine iOS-Kamera zum Generieren von Frames verwenden, können zur Verarbeitung in das CVPixelBuffer-Format konvertiert werden, bevor sie im Livestream-Modus an den Bildeinbetter gesendet werden.

Swift

// Obtain a CVPixelBuffer.

// Convert the `CVPixelBuffer` object to a MediaPipe's Image object having the default
// orientation `UIImage.Orientation.up`.
let image = try MPImage(pixelBuffer: pixelBuffer)
    

Objective-C

// Obtain a CVPixelBuffer.

// Convert the `CVPixelBuffer` object to a MediaPipe's Image object having the
// default orientation `UIImageOrientationUp`.
MPImage *image = [[MPPImage alloc] initWithUIImage:image error:nil];
    

Weitere Informationen zu CVPixelBuffer findest du in der CVPixelBuffer-Entwicklerdokumentation von Apple.

CMSampleBuffer

Im CMSampleBuffer-Format werden Mediensamples eines einheitlichen Medientyps gespeichert. Es eignet sich gut für den Livestream-Ausführungsmodus. Live-Frames von iOS-Kameras werden asynchron im CMSampleBuffer-Format von iOS AVCaptureVideoDataOutput bereitgestellt.

Swift

// Obtain a CMSampleBuffer.

// Convert the `CMSampleBuffer` object to a MediaPipe's Image object having the default
// orientation `UIImage.Orientation.up`.
let image = try MPImage(sampleBuffer: sampleBuffer)
    

Objective-C

// Obtain a `CMSampleBuffer`.

// Convert the `CMSampleBuffer` object to a MediaPipe's Image object having the
// default orientation `UIImageOrientationUp`.
MPImage *image = [[MPPImage alloc] initWithSampleBuffer:sampleBuffer error:nil];
    

Weitere Informationen zu CMSampleBuffer findest du in der CMSampleBuffer-Entwicklerdokumentation von Apple.

Aufgabe ausführen

Verwenden Sie zum Ausführen des Bild-Embedders die embed()-Methode, die dem zugewiesenen Ausführungsmodus entspricht:

  • Standbild: embed(image:)
  • Video: embed(videoFrame:timestampInMilliseconds:)
  • Livestream: embedAsync(image:timestampInMilliseconds:)

Die folgenden Codebeispiele zeigen einfache Beispiele für die Ausführung des Bild-Embedders in diesen verschiedenen Ausführungsmodi:

Swift

Bild

let result = try imageEmbedder.embed(image: image)
    

Video

let result = try imageEmbedder.embed(
  videoFrame: image,
  timestampInMilliseconds: timestamp)
    

Livestream

try imageEmbedder.embedAsync(
  image: image,
  timestampInMilliseconds: timestamp)
    

Objective-C

Bild

MPPImageEmbedderResult *result =
  [imageEmbedder embedImage:image error:nil];
    

Video

MPPImageEmbedderResult *result =
  [imageEmbedder embedVideoFrame:image
           timestampInMilliseconds:timestamp
                             error:nil];
    

Livestream

BOOL success =
  [imageEmbedder embedAsyncImage:image
           timestampInMilliseconds:timestamp
                             error:nil];
    

Im Codebeispiel für den Bild-Embedder werden die Implementierungen der einzelnen Modi embed(image:), embed(videoFrame:timestampInMilliseconds:) und embedAsync(image:timestampInMilliseconds:) genauer erläutert. Mit dem Beispielcode kann der Nutzer zwischen Verarbeitungsmodi wechseln, die für Ihren Anwendungsfall möglicherweise nicht erforderlich sind.

Wichtige Hinweise:

  • Wenn Sie im Video- oder Livestream-Modus ausführen, müssen Sie der Aufgabe „Image Embedder“ auch den Zeitstempel des Eingabeframes angeben.

  • Wenn die Ausführung im Bild- oder Videomodus erfolgt, blockiert die Aufgabe „Image Embedder“ den aktuellen Thread, bis die Verarbeitung des Eingabebilds oder ‑frames abgeschlossen ist. Um das Blockieren des aktuellen Threads zu vermeiden, führen Sie die Verarbeitung in einem Hintergrund-Thread mithilfe der iOS-Frameworks Dispatch oder NSOperation aus. Wenn Ihre App mit Swift erstellt wurde, können Sie auch Swift-Parallelität für die Ausführung von Hintergrundthreads verwenden.

  • Wenn die Ausführung im Livestream-Modus erfolgt, gibt die Aufgabe „Image Embedder“ sofort eine Antwort zurück und blockiert den aktuellen Thread nicht. Nachdem jeder Eingabeframe eingebettet wurde, wird die Methode imageEmbedder(_:didFinishEmbedding:timestampInMilliseconds:error:) mit den Ergebnissen aufgerufen. Der Image Embedder ruft diese Methode asynchron über eine dedizierte serielle Weiterleitungswarteschlange auf. Wenn Sie die Ergebnisse auf der Benutzeroberfläche anzeigen möchten, senden Sie sie nach der Verarbeitung an die Hauptwarteschlange. Wenn die Funktion embedAsync aufgerufen wird, während in der Aufgabe „Bild einbetten“ ein anderer Frame verarbeitet wird, ignoriert der Bildeinbetter den neuen Eingabeframe.

Ergebnisse verarbeiten und anzeigen

Nach der Ausführung der Inferenz gibt der Bild-Embedding-Dienst ein ImageEmbedderResult-Objekt zurück, das eine Liste von Einbettungen (entweder mit Gleitkommazahlen oder skalarquantisiert) für das Eingabebild enthält.

Im Folgenden sehen Sie ein Beispiel für die Ausgabedaten dieser Aufgabe:

ImageEmbedderResult:
  Embedding #0 (sole embedding head):
    float_embedding: {0.0, 0.0, ..., 0.0, 1.0, 0.0, 0.0, 2.0}
    head_index: 0

Dieses Ergebnis wurde durch das Einbetten des folgenden Bildes erzielt:

Mit der Funktion ImageEmbedder.cosineSimilarity können Sie die Ähnlichkeit zweier Embeddings vergleichen.

Swift

let similarity = try ImageEmbedder.cosineSimilarity(
  embedding1: result.embeddingResult.embeddings[0],
  embedding2: otherResult.embeddingResult.embeddings[0])
    

Objective-C

NSNumber *similarity = [MPPImageEmbedder
      cosineSimilarityBetweenEmbedding1:result.embeddingResult.embeddings[0]
                          andEmbedding2:otherResult.embeddingResult.embeddings[0]
                                  error:nil];