ML Kit bietet ein optimiertes SDK für die Selfie-Segmentierung. Die Selfie Segmenter-Assets sind zum Zeitpunkt der Erstellung statisch mit Ihrer App verknüpft. Dadurch wird die App-Größe um bis zu 24 MB erhöht und die API-Latenz kann je nach Größe des Eingabebilds (gemessen auf dem iPhone X) zwischen 7 ms und 12 ms variieren.
Ausprobieren
- Probieren Sie die Beispiel-App aus, um ein Beispiel für die Verwendung dieser API zu sehen.
Hinweis
Fügen Sie die folgenden ML Kit-Bibliotheken in Ihre Podfile-Datei ein:
pod 'GoogleMLKit/SegmentationSelfie', '3.2.0'
Nachdem Sie die Pods Ihres Projekts installiert oder aktualisiert haben, öffnen Sie Ihr Xcode-Projekt mit der
xcworkspace
. ML Kit wird ab Xcode-Version 13.2.1 unterstützt.
1. Instanz von Segmenter erstellen
Um ein Selfie zu segmentieren, erstellen Sie zuerst eine Instanz von Segmenter
mit SelfieSegmenterOptions
und geben Sie optional die Segmentierungseinstellungen an.
Segmentierungsoptionen
Segmentierungsmodus
Für Segmenter
gibt es zwei Modi. Wählen Sie die Option aus, die zu Ihrem Anwendungsfall passt.
STREAM_MODE (default)
Dieser Modus ist für das Streamen von Frames aus dem Video oder der Kamera vorgesehen. In diesem Modus nutzt der Segmentierer die Ergebnisse früherer Frames, um eine flüssigere Segmentierung zu ermöglichen.
SINGLE_IMAGE_MODE (default)
Dieser Modus ist für einzelne Bilder geeignet, die keinen Bezug haben. In diesem Modus verarbeitet die Segmentierung jedes Bild unabhängig und ohne Glättung über Frames.
Maske für Rohgröße aktivieren
Fordert den Segmentierer auf, die Rohgrößenmaske zurückzugeben, die der Größe der Modellausgabe entspricht.
Die Größe der Rohmaske (z.B. 256 x 256) ist normalerweise kleiner als die Größe des Eingabebilds.
Ohne Angabe dieser Option skaliert der Segmentierer die Rohmaske neu, damit sie der Eingabebildgröße entspricht. Verwenden Sie diese Option, wenn Sie eine benutzerdefinierte Neuskalierungslogik anwenden möchten oder für Ihren Anwendungsfall keine Neuskalierung erforderlich ist.
Geben Sie die Segmentierungsoptionen an:
Swift
let options = SelfieSegmenterOptions() options.segmenterMode = .singleImage options.shouldEnableRawSizeMask = true
Objective-C
MLKSelfieSegmenterOptions *options = [[MLKSelfieSegmenterOptions alloc] init]; options.segmenterMode = MLKSegmenterModeSingleImage; options.shouldEnableRawSizeMask = YES;
Rufen Sie abschließend eine Instanz von Segmenter
ab. Übergeben Sie die angegebenen Optionen:
Swift
let segmenter = Segmenter.segmenter(options: options)
Objective-C
MLKSegmenter *segmenter = [MLKSegmenter segmenterWithOptions:options];
2. Eingabebild vorbereiten
Gehen Sie für jedes Bild bzw. jeden Videoframe so vor, um Selfies zu segmentieren.
Wenn Sie den Streammodus aktiviert haben, müssen Sie VisionImage
-Objekte aus CMSampleBuffer
s erstellen.
Erstellen Sie mit UIImage
oder CMSampleBuffer
ein VisionImage
-Objekt.
Wenn du UIImage
verwendest, gehe so vor:
- Erstellen Sie mit der
UIImage
einVisionImage
-Objekt. Achte 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 du CMSampleBuffer
verwendest, gehe so vor:
-
Geben Sie 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 mit dem Objekt
CMSampleBuffer
und der Ausrichtung einVisionImage
-Objekt: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 das Objekt VisionImage
an eine der Bildverarbeitungsmethoden der Segmenter
. Sie können entweder die asynchrone process(image:)
-Methode oder die synchrone results(in:)
-Methode verwenden.
So führen Sie eine synchrone Segmentierung eines Selfies durch:
Swift
var mask: [SegmentationMask] do { mask = try segmenter.results(in: image) } catch let error { print("Failed to perform segmentation with error: \(error.localizedDescription).") return } // Success. Get a segmentation mask here.
Objective-C
NSError *error; MLKSegmentationMask *mask = [segmenter resultsInImage:image error:&error]; if (error != nil) { // Error. return; } // Success. Get a segmentation mask here.
So führen Sie die Segmentierung eines Selfies asynchron durch:
Swift
segmenter.process(image) { mask, error in guard error == nil else { // Error. return } // Success. Get a segmentation mask here.
Objective-C
[segmenter processImage:image completion:^(MLKSegmentationMask * _Nullable mask, NSError * _Nullable error) { if (error != nil) { // Error. return; } // Success. Get a segmentation mask here. }];
4. Segmentierungsmaske abrufen
So erhalten Sie das Segmentierungsergebnis:
Swift
let maskWidth = CVPixelBufferGetWidth(mask.buffer) let maskHeight = CVPixelBufferGetHeight(mask.buffer) CVPixelBufferLockBaseAddress(mask.buffer, CVPixelBufferLockFlags.readOnly) let maskBytesPerRow = CVPixelBufferGetBytesPerRow(mask.buffer) var maskAddress = CVPixelBufferGetBaseAddress(mask.buffer)!.bindMemory( to: Float32.self, capacity: maskBytesPerRow * maskHeight) for _ in 0...(maskHeight - 1) { for col in 0...(maskWidth - 1) { // Gets the confidence of the pixel in the mask being in the foreground. let foregroundConfidence: Float32 = maskAddress[col] } maskAddress += maskBytesPerRow / MemoryLayout<Float32>.size }
Objective-C
size_t width = CVPixelBufferGetWidth(mask.buffer); size_t height = CVPixelBufferGetHeight(mask.buffer); CVPixelBufferLockBaseAddress(mask.buffer, kCVPixelBufferLock_ReadOnly); size_t maskBytesPerRow = CVPixelBufferGetBytesPerRow(mask.buffer); float *maskAddress = (float *)CVPixelBufferGetBaseAddress(mask.buffer); for (int row = 0; row < height; ++row) { for (int col = 0; col < width; ++col) { // Gets the confidence of the pixel in the mask being in the foreground. float foregroundConfidence = maskAddress[col]; } maskAddress += maskBytesPerRow / sizeof(float); }
Ein vollständiges Beispiel für die Verwendung der Segmentierungsergebnisse finden Sie im ML Kit-Schnellstartbeispiel.
Tipps zur Leistungsverbesserung
Die Qualität der Ergebnisse hängt von der Qualität des Eingabebilds ab:
- Damit das ML Kit ein genaues Segmentierungsergebnis erhält, sollte das Bild mindestens 256 × 256 Pixel groß sein.
- Wenn Sie die Selfie-Segmentierung in einer Echtzeitanwendung durchführen, sollten Sie auch die Gesamtabmessungen der Eingabebilder berücksichtigen. Kleinere Bilder können schneller verarbeitet werden. Um die Latenz zu verringern, sollten Sie Bilder mit niedrigeren Auflösungen aufnehmen. Beachten Sie jedoch die oben genannten Auflösungsanforderungen und achten Sie darauf, dass das Motiv so viel wie möglich einnimmt.
- Ein schlechter Bildfokus kann sich auch auf die Genauigkeit auswirken. Sollten Sie keine akzeptablen Ergebnisse erhalten, bitten Sie den Nutzer, das Bild neu aufzunehmen.
Wenn Sie die Segmentierung in einer Echtzeitanwendung verwenden möchten, beachten Sie die folgenden Richtlinien, um die besten Frame-Raten zu erzielen:
- Verwenden Sie den Segmentierungsmodus
stream
. - Nehmen Sie Bilder mit einer niedrigeren Auflösung auf. Beachten Sie jedoch auch die Anforderungen dieser API an die Bildabmessung.
- Verwenden Sie zum Verarbeiten von Videoframes die synchrone
results(in:)
API des Segmentierers. Rufen Sie diese Methode aus der Funktion captureOutput(_, didOutput:from:) von AVCaptureVideoDataOutputSampleBufferDelegate auf, um synchron Ergebnisse aus dem angegebenen Videoframe abzurufen. Belassen Sie das Attribut alwaysDiscardsLateVideoFrames von AVCaptureVideoDataOutput auf „true“, um Aufrufe an den Segmentierer zu drosseln. Steht ein neuer Videoframe zur Verfügung, während die Segmentierung ausgeführt wird, wird dieser entfernt. - Wenn Sie die Ausgabe des Segmentierers verwenden, um Grafiken auf dem Eingabebild einzublenden, rufen Sie zuerst das Ergebnis aus dem ML Kit ab und rendern Sie dann das Bild und das Overlay in einem einzigen Schritt. Auf diese Weise rendern Sie für jeden verarbeiteten Eingabeframe nur einmal auf der Anzeigeoberfläche. Ein Beispiel finden Sie in den Klassen previewOverlayView und CameraViewController im ML Kit-Schnellstartbeispiel.