Leitfaden zur Bildsegmentierung für iOS

Mit der Aufgabe "Bildsegmentierung" können Sie Bilder basierend auf vordefinierten und visuelle Effekte wie das Weichzeichnen des Hintergrunds anwenden. Diese Anleitung zur Verwendung des Bildsegmenters mit iOS-Apps.

Das in dieser Anleitung beschriebene Codebeispiel ist auf GitHub

Sie können diese Aufgabe in Aktion sehen, indem Sie die Webseite Weitere Informationen zu Funktionen, Modellen und Konfigurationsoptionen sehen Sie sich die Übersicht:

Codebeispiel

Das Codebeispiel von MediaPipe Tasks enthält eine einfache Implementierung eines Bildsegmenter-App für iOS

In diesem Beispiel wird ein Bildsegmentierer implementiert, der Kategoriemasken ausgibt. Sie verwendet in die Kamera eines physischen iOS-Geräts, um die Bildsegmentierung bei einem Live-Videostream durchzuführen. Kamerafeed oder zu Bildern und Videos aus der Gerätegalerie hinzufügen.

Du kannst die App als Ausgangspunkt für deine eigene iOS-App verwenden oder darauf verweisen wenn Sie eine vorhandene App ändern. Der Beispielcode für die Bildsegmentierung wird auf GitHub

Code herunterladen

In der folgenden Anleitung erfahren Sie, wie Sie eine lokale Kopie des Beispiels erstellen. mit dem Befehlszeilentool git 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. Konfigurieren Sie optional Ihre Git-Instanz für den Sparse-Checkout, damit Sie nur die Dateien für die Beispiel-App "Image Segmenter" verwenden:

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

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

Schlüsselkomponenten

Die folgenden Dateien enthalten den wichtigen Code für das Beispiel des Bildsegmenters Anwendung:

  • ImageSegmenterService.swift: Initialisiert den Image Segmenter, übernimmt die Modellauswahl und führt auf die Eingabedaten zurückführen.
  • CameraViewController.swift: Implementiert die Benutzeroberfläche für den Live-Kamerafeed-Eingabemodus und visualisiert die Ergebnisse.
  • MediaLibraryViewController.swift Implementiert die Benutzeroberfläche für den Eingabemodus für Standbilder und Videodateien und und visualisiert die Ergebnisse.

Einrichtung

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

Abhängigkeiten

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

Eine Anleitung zur Installation von CocoaPods unter macOS findest du im Artikel zu CocoaPods Installationsanleitung. Eine Anleitung zum Erstellen eines Podfile mit den für Ihr Projekt erforderlichen Pods erhalten Sie unter Verwendung CocoaPods

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

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

Falls Ihre App Einheitentestziele enthält, lesen Sie den Einrichtungsleitfaden für iOS: Weitere Informationen zur Einrichtung Dein Podfile.

Modell

Für die Aufgabe „MediaPipe Image Segmenter“ ist ein trainiertes Modell erforderlich, bei dieser Aufgabe. Weitere Informationen zu den verfügbaren trainierten Modellen für Bildsegmentierung, siehe Aufgabenübersicht 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 Verwalten von Dateien und Ordner in Ihrem Xcode Projekt.

Verwenden Sie das Attribut BaseOptions.modelAssetPath, um den Pfad zum Modell anzugeben in deinem App Bundle. Ein Codebeispiel finden Sie im nächsten Abschnitt.

Aufgabe erstellen

Sie können die Image Segmenter-Aufgabe erstellen, indem Sie einen seiner Initialisierer aufrufen. Die Der ImageSegmenter(options:)-Initialisierer akzeptiert Werte für die Konfiguration Optionen.

Wenn Sie keinen Bildsegmenter benötigen, der mit einer benutzerdefinierten Konfiguration initialisiert wurde können Sie mit dem ImageSegmenter(modelPath:)-Initialisierer ein Image Segmenter mit den Standardoptionen Weitere Informationen zur Konfiguration finden Sie unter Konfigurationsübersicht.

Die Aufgabe „Bildsegmentierung“ unterstützt drei Eingabedatentypen: Standbilder, Videodateien und Live-Videostreams. Standardmäßig initialisiert ImageSegmenter(modelPath:) einen für Standbilder angelangt. Wenn Sie möchten, dass Ihre Aufgabe für die Verarbeitung von Videos initialisiert wird Dateien oder Live-Videostreams verwenden, geben Sie das Video mit ImageSegmenter(options:) an oder den Livestream-Laufmodus. Der Livestream-Modus erfordert außerdem die zusätzlichen imageSegmenterLiveStreamDelegate, mit der die Image Segmenter , um Bildsegmentierungsergebnisse an den Bevollmächtigten zu senden asynchron programmiert.

Wählen Sie den Tab für Ihren Ausführungsmodus aus, um zu sehen, wie die Aufgabe erstellt wird und eine Inferenz ausführen.

Swift

Bild

import MediaPipeTasksVision

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

let options = ImageSegmenterOptions()
options.baseOptions.modelAssetPath = modelPath
options.runningMode = .image
options.shouldOutputCategoryMask = true
options.shouldOutputConfidenceMasks = false

let imageSegmenter = try ImageSegmenter(options: options)
    

Video

import MediaPipeTasksVision

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

let options = ImageSegmenterOptions()
options.baseOptions.modelAssetPath = modelPath
options.runningMode = .video
options.shouldOutputCategoryMask = true
options.shouldOutputConfidenceMasks = false

let imageSegmenter = try ImageSegmenter(options: options)
    

Livestream

import MediaPipeTasksVision

// Class that conforms to the `imageSegmenterLiveStreamDelegate` protocol and
// implements the method that the image segmenter calls once it finishes
// performing segmentation of each input frame.
class ImageSegmenterResultProcessor: NSObject, ImageSegmenterLiveStreamDelegate {

  func imageSegmenter(
    _ imageSegmenter: ImageSegmenter,
    didFinishSegmentation result: ImageSegmenterResult?,
    timestampInMilliseconds: Int,
    error: Error?) {

    // Process the image segmentation result or errors here.

  }
}

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

let options = ImageSegmenterOptions()
options.baseOptions.modelAssetPath = modelPath
options.runningMode = .liveStream
options.shouldOutputCategoryMask = true
options.shouldOutputConfidenceMasks = false

// Set `imageSegmenterLiveStreamDelegate` to the object of the class that
// confirms to the `ImageSegmenterLiveStreamDelegate` protocol.
let processor = ImageSegmenterResultProcessor()
options.imageSegmenterLiveStreamDelegate = processor

let imageSegmenter = try ImageSegmenter(options: options)
    

Objective-C

Bild

@import MediaPipeTasksVision;

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

MPPImageSegmenterOptions *options = [[MPPImageSegmenterOptions alloc] init];
options.baseOptions.modelAssetPath = modelPath;
options.runningMode = MPPRunningModeImage;
options.shouldOutputCategoryMask = YES;
options.shouldOutputConfidenceMasks = NO;

MPPImageSegmenter *imageSegmenter =
  [[MPPImageSegmenter alloc] initWithOptions:options error:nil];
    

Video

@import MediaPipeTasksVision;

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

MPPImageSegmenterOptions *options = [[MPPImageSegmenterOptions alloc] init];
options.baseOptions.modelAssetPath = modelPath;
options.runningMode = MPPRunningModeVideo;
options.shouldOutputCategoryMask = YES;
options.shouldOutputConfidenceMasks = NO;

MPPImageSegmenter *imageSegmenter =
  [[MPPImageSegmenter alloc] initWithOptions:options error:nil];
    

Livestream

@import MediaPipeTasksVision;

// Class that conforms to the `MPPImageSegmenterLiveStreamDelegate` protocol
// and implements the method that the image segmenter calls once it finishes
// performing segmentation of each input frame.

@interface APPImageSegmenterResultProcessor : NSObject 

@end

@implementation APPImageSegmenterResultProcessor

-   (void)imageSegmenter:(MPPImageSegmenter *)imageSegmenter
    didFinishSegmentationWithResult:(MPPImageSegmenterResult *)imageSegmenterResult
         timestampInMilliseconds:(NSInteger)timestampInMilliseconds
                           error:(NSError *)error {

    // Process the image segmentation result or errors here.

}

@end

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

MPPImageSegmenterOptions *options = [[MPPImageSegmenterOptions alloc] init];
options.baseOptions.modelAssetPath = modelPath;
options.runningMode = MPPRunningModeLiveStream;
options.shouldOutputCategoryMask = YES;
options.shouldOutputConfidenceMasks = NO;

// Set `imageSegmenterLiveStreamDelegate` to the object of the class that
// confirms to the `MPPImageSegmenterLiveStreamDelegate` protocol.
APPImageSegmenterResultProcessor *processor =
  [APPImageSegmenterResultProcessor new];
options.imageSegmenterLiveStreamDelegate = processor;

MPPImageSegmenter *imageSegmenter =
  [[MPPImageSegmenter alloc] initWithOptions:options error:nil];
    

Mit dem Beispielcode für die Bildsegmentierung können Nutzer zwischen Verarbeitungsmodi. Dieser Ansatz macht den Code zur Aufgabenerstellung komplizierter und ist möglicherweise für Ihren Anwendungsfall ungeeignet.

Konfigurationsoptionen

Diese Aufgabe bietet die folgenden Konfigurationsoptionen für iOS-Apps:

Option Beschreibung Wertebereich Standardwert
runningMode Legt den Ausführungsmodus für die Task fest. Es gibt drei Modi:

IMAGE: Der Modus für Einzelbildeingaben.

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

LIVE_STREAM: Der Modus für einen Livestream mit Eingabe zum Beispiel von einer Kamera. In diesem Modus: ImageSegmenterLiveStreamDelegate muss auf eine Instanz einer Klasse festgelegt sein, die das ImageSegmenterLiveStreamDelegate, um die Segmentierung zu erhalten asynchron Ergebnisse liefern.
{RunningMode.image, RunningMode.video, RunningMode.liveStream} RunningMode.image
shouldOutputCategoryMask Wenn True festgelegt ist, enthält die Ausgabe eine Segmentierungsmaske als Uint8-Bild, wobei jeder Pixelwert die Gewinnerkategorie angibt Wert. {True, False} False
shouldOutputConfidenceMasks Wenn True festgelegt ist, enthält die Ausgabe eine Segmentierungsmaske als Gleitkommawert, wobei jeder Gleitkommawert den Konfidenzwert darstellt Kurzübersicht der Kategorie. {True, False} True
displayNamesLocale Legt die Sprache der Labels fest, die für Anzeigenamen in der Metadaten des Aufgabenmodells, falls verfügbar. Standardwert ist en für Englisch. Sie können den Metadaten eines benutzerdefinierten Modells lokalisierte Labels hinzufügen mit der TensorFlow Lite Metadata Writer API Gebietsschemacode de
result_callback Legt den Ergebnis-Listener fest, der die Segmentierungsergebnisse empfangen soll asynchron, wenn sich der Bildsegmentierer im LIVE_STREAM-Modus befindet. Kann nur verwendet werden, wenn der Ausführungsmodus auf LIVE_STREAM festgelegt ist

Wenn der Laufmodus auf LIVE_STREAM festgelegt ist, benötigt der Bildsegmentierer das zusätzliche imageSegmenterLiveStreamDelegate-Konfigurationsoption, die ermöglicht es dem Bildsegmentierer, Bildsegmentierungsergebnisse asynchron zu liefern. Der Bevollmächtigte muss den Parameter Methode imageSegmenter(_:didFinishSegmentation:timestampInMilliseconds:error:), der vom Image Segmenter aufgerufen wird, nachdem die Ergebnisse die Segmentierung jedes Frames.

Optionsname Beschreibung Wertebereich Standardwert
imageSegmenterLiveStreamDelegate Aktiviert den Bildsegmentierungs-Assistenten, um die Ergebnisse für die Durchführung von Bildern zu erhalten die Segmentierung asynchron im Livestream-Modus. Die Klasse, deren Instanz auf diese Eigenschaft gesetzt ist, muss imageSegmenter(_:didFinishSegmentation:timestampInMilliseconds:error:) . Nicht zutreffend Nicht festgelegt

Daten vorbereiten

Konvertieren Sie das Eingabebild oder den Eingabe-Frame zuerst in ein MPImage-Objekt, und übergeben es an den Bildsegmenter. MPImage unterstützt verschiedene Arten von iOS-Bildern Formate und können sie in jedem ausgeführten Modus für die Inferenz verwenden. Weitere Informationen Informationen zu MPImage finden Sie in der MPImage-API

Wählen Sie je nach Anwendungsfall und Laufmodus ein iOS-Bildformat aus. Anwendung erforderlich.MPImage akzeptiert die UIImage, CVPixelBuffer und CMSampleBuffer iOS-Bildformate.

UIImage

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

  • Bilder: Bilder aus einem App Bundle, einer Nutzergalerie oder einem Dateisystem, die wie folgt formatiert sind: UIImage-Bilder können in ein MPImage-Objekt konvertiert werden.

  • Videos: Verwenden Sie AVAssetImageGenerator. zum Extrahieren von Videoframes CGImage Format und konvertieren Sie sie in UIImage Bilder.

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];
    

In diesem Beispiel wird ein MPImage mit dem Standardwert UIImage.Orientation.Up Ausrichtung. Sie können MPImage mit einer der unterstützten UIImage.Orientation Werte. Die Bildsegmentierung unterstützt keine gespiegelten Ausrichtungen wie .upMirrored, .downMirrored, .leftMirrored, .rightMirrored.

Weitere Informationen zu UIImage findest du unter UIImage Apple Developer Dokumentation.

CVPixelBuffer

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

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

  • Bilder: Apps, die nach einer Verarbeitung CVPixelBuffer Bilder generieren mit dem CoreImage-Framework von iOS an den Bildsegmentator im Bildlaufmodus.

  • Videos: Videoframes können für folgendes Format in das CVPixelBuffer-Format konvertiert werden: verarbeitet und dann im Videomodus an den Bildsegmenter gesendet.

  • Livestream: Apps, die mit einer iOS-Kamera Frames generieren, werden möglicherweise zur Verarbeitung in das CVPixelBuffer-Format konvertiert, bevor sie an den Bildsegmentierung im Livestream-Modus

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 finden Sie in der CVPixelBuffer Apple-Dokumentation Entwickler*in Dokumentation.

CMSampleBuffer

Das Format CMSampleBuffer speichert Medienbeispiele eines einheitlichen Medientyps und ist eignet sich gut für den Livestream-Laufmodus. Live-Frames von iOS-Kameras asynchron im CMSampleBuffer-Format von iOS bereitgestellt AVCaptureVideoDataOutput.

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 finden Sie im Artikel CMSampleBuffer Apple“. Entwickler*in Dokumentation.

Aufgabe ausführen

Verwenden Sie zum Ausführen des Bildsegmentierers die segment()-Methode für das zugewiesene Laufmodus:

  • Standbild: segment(image:)
  • Video: segment(videoFrame:timestampInMilliseconds:)
  • Livestream: segmentAsync(image:timestampInMilliseconds:)

Die folgenden Codebeispiele zeigen einfache Beispiele für die Ausführung von Image Segmenter in verschiedene Laufmodi zu testen:

Swift

Bild

let result = try imageSegmenter.segment(image: image)
    

Video

let result = try imageSegmenter.segment(
  videoFrame: image,
  timestampInMilliseconds: timestamp)
    

Livestream

try imageSegmenter.segmentAsync(
  image: image,
  timestampInMilliseconds: timestamp)
    

Objective-C

Bild

MPPImageSegmenterResult *result =
  [imageSegmenter segmentImage:image error:nil];
    

Video

MPPImageSegmenterResult *result =
  [imageSegmenter segmentVideoFrame:image
            timestampInMilliseconds:timestamp
                              error:nil];
    

Livestream

BOOL success =
  [imageSegmenter segmentAsyncImage:image
            timestampInMilliseconds:timestamp
                              error:nil];
    

Das Codebeispiel für die Bildsegmentierung zeigt die Implementierungen dieser Modi. segment(image:), segment(videoFrame:timestampInMilliseconds:) und segmentAsync(image:timestampInMilliseconds:)

Wichtige Hinweise:

  • Im Video- oder Livestreammodus müssen Sie auch die Zeitstempel des Eingabe-Frames für die Bildsegmentierungs-Task.

  • Im Bild- oder Videomodus blockiert die Aufgabe aktuellen Thread zu schreiben, bis die Verarbeitung des Eingabebilds oder -frames abgeschlossen ist. Bis Blockieren des aktuellen Threads vermeiden, Verarbeitung im Hintergrund ausführen Threads unter iOS verwenden Versand oder NSOperation Frameworks.

  • Im Livestream-Modus wird die Aufgabe "Bildsegmentierung" sofort zurückgegeben. und blockiert den aktuellen Thread nicht. Es ruft die Methode imageSegmenter(_:didFinishSegmentation:timestampInMilliseconds:error:) mit dem Bildsegmentator nach der Verarbeitung jedes Eingabe-Frames hinzu. Die Image Segmenter ruft diese Methode asynchron auf einer dedizierten Weiterleitungswarteschlange. Erstellen Sie zum Anzeigen der Ergebnisse auf der Benutzeroberfläche den Befehl nach der Verarbeitung der Ergebnisse an die Hauptwarteschlange. Wenn die Die Funktion segmentAsync wird aufgerufen, wenn die Aufgabe „Bildsegmentierung“ ausgelastet ist verarbeitet, wird der neue Eingabe-Frame ignoriert.

Ergebnisse verarbeiten und anzeigen

Beim Ausführen einer Inferenz gibt die Image-Segmenter-Aufgabe eine ImageSegmenterResult zurück. -Objekt, das die Ergebnisse der Segmentierungsaufgabe enthält. Der Inhalt der die Ausgabe hängt vom Ausgabetyp ab, den Sie beim konfiguriert die Aufgabe zu erledigen.

Die folgenden Bilder zeigen eine Visualisierung der Aufgabenausgabe für eine Kategorie Wertmaske. Der Bereich der Kategoriemaske ist [0, 255] und jeder Pixelwert stellt den erfolgreichen Kategorieindex der Modellausgabe dar. Die Gewinnerkategorie Index die höchste Punktzahl unter den Kategorien hat, die das Modell erkennen kann.

Ausgabe des Originalbilds und der Kategoriemaske. Quell-Image von Pascal VOC 2012 Dataset.

Der Beispielcode für die Bildsegmentierung zeigt, wie der Bildsegmentator angezeigt wird. finden Sie im Code Beispiel .