ML Kit bietet ein optimiertes SDK für die Segmentierung von Selfies. Die Assets des Selfie-Segmenters sind bei der Erstellung statisch mit Ihrer App verknüpft. Dadurch wird die Größe Ihrer App um bis zu 24 MB erhöht und die API-Latenz kann abhängig von der Größe des Eingabebildes (bei der Messung auf dem iPhone X) zwischen ~7 ms und 12 ms variieren.
Jetzt ausprobieren
- Probieren Sie die Beispiel-App aus, um sehen Sie sich ein Anwendungsbeispiel für diese API an.
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 zugehörigen .
xcworkspace
-Datei. ML Kit wird ab Xcode-Version 13.2.1 unterstützt.
1. Instanz von Segmenter erstellen
Wenn Sie ein Selfie-Bild segmentieren möchten, erstellen Sie zuerst eine Instanz von Segmenter
mit SelfieSegmenterOptions
und geben Sie optional die Segmentierungseinstellungen an.
Segmentierungsoptionen
Segmentierungsmodus
Der Segmenter
wird in zwei Modi ausgeführt. Wählen Sie die Option aus, die zu Ihrem Anwendungsfall passt.
STREAM_MODE (default)
Dieser Modus ist zum Streamen von Frames über ein Video oder eine Kamera vorgesehen. In diesem Modus verwendet der Segmentierungsoperator Ergebnisse aus vorherigen Frames, um flüssigere Segmentierungsergebnisse zurückzugeben.
SINGLE_IMAGE_MODE (default)
Dieser Modus ist für einzelne Bilder vorgesehen, die keinen Bezug haben. In diesem Modus verarbeitet der Segmenter jedes Bild unabhängig und ohne Glättung über die Frames.
Maske für Rohgröße aktivieren
Fordert den Segmenter 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 Segmenter die Rohmaske neu, damit sie der Größe des eingegebenen Bilds 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;
Schließlich rufen Sie 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
So segmentieren Sie Selfies für jedes Bild oder jeden Frame des Videos:
Wenn Sie den Streammodus aktiviert haben, müssen Sie VisionImage
-Objekte erstellen aus
CMSampleBuffer
.
Erstellen Sie ein VisionImage
-Objekt mithilfe von UIImage
oder einem
CMSampleBuffer
Wenn du ein UIImage
verwendest, gehe so vor:
- Erstellen Sie ein
VisionImage
-Objekt mit derUIImage
. Geben Sie die richtige.orientation
an.Swift
let image = VisionImage(image: UIImage) visionImage.orientation = image.imageOrientation
Objective-C
MLKVisionImage *visionImage = [[MLKVisionImage alloc] initWithImage:image]; visionImage.orientation = image.imageOrientation;
Wenn du ein CMSampleBuffer
verwendest, gehe so vor:
-
Geben Sie die Ausrichtung der Bilddaten an, die in der
CMSampleBuffer
So ermitteln Sie die Bildausrichtung:
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; } }
- Erstellen Sie ein
VisionImage
-Objekt mithilfe derCMSampleBuffer
-Objekt und 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 das VisionImage
-Objekt an eine der Bildverarbeitungsmethoden von Segmenter
. Sie können entweder die asynchrone Methode process(image:)
oder die synchrone Methode results(in:)
verwenden.
So segmentieren Sie ein Selfie synchron:
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
Sie können das Segmentierungsergebnis so erhalten:
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 in der ML Kit-Schnellstartbeispiel.
Tipps zur Verbesserung der Leistung
Die Qualität Ihrer Ergebnisse hängt von der Qualität des Eingabebildes ab:
- Damit ML Kit ein genaues Segmentierungsergebnis erhalten kann, sollte das Bild mindestens 256 x 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, nehmen Sie Bilder mit einer niedrigeren Auflösung auf. Beachten Sie jedoch die oben genannten Anforderungen an die Auflösung und achten Sie darauf, dass die Person so viel wie möglich auf dem Bild einnimmt.
- Ein schlechter Bildfokus kann auch die Genauigkeit beeinträchtigen. Wenn Sie keine akzeptablen Ergebnisse erhalten, bitten Sie den Nutzer, das Bild erneut aufzunehmen.
Wenn Sie die Segmentierung in einer Echtzeitanwendung verwenden möchten, beachten Sie die folgenden Richtlinien, um die besten Framerates 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 Bildabmessungen.
- Verwende zur Verarbeitung von Videoframes die synchrone
results(in:)
API des Segmenters. Rufen Sie diese Methode aus der Funktion captureOutput(_, didOutput:from:) von AVCaptureVideoDataOutputSampleBufferDelegate auf, um synchron Ergebnisse aus dem angegebenen Videoframe abzurufen. Behalten Sie für AVCaptureVideoDataOutput die Einstellung alwaysDiscardsLateVideoFrames auf „true“ bei, um Aufrufe an den Segmenter zu drosseln. Wenn ein neuer Videoframe verfügbar wird, während die Segmentierung ausgeführt wird, wird dieser entfernt. - Wenn Sie die Ausgabe des Segmenters verwenden, um Grafiken über das Eingabebild zu blenden, rufen Sie zuerst das Ergebnis aus ML Kit ab und rendern Sie dann das Bild und das Overlay in einem Schritt. Auf diese Weise rendern Sie auf der Anzeigeoberfläche nur einmal für jeden verarbeiteten Eingabe-Frame. Ein Beispiel finden Sie in den Klassen previewOverlayView und CameraViewController im Beispiel für ML Kit-Kurzanleitung.