ML Kit bietet ein optimiertes SDK für die Selfie-Segmentierung. Die Assets des Selfie-Segmentierers werden zur Build-Zeit statisch mit Ihrer App verknüpft. Dadurch erhöht sich die Größe Ihrer App um bis zu 24 MB. Die API-Latenz kann je nach Bildgröße der Eingabe zwischen etwa 7 ms und etwa 12 ms liegen (gemessen auf einem iPhone X).
Jetzt ausprobieren
- Probieren Sie die Beispiel-App aus, um ein Anwendungsbeispiel für diese API zu sehen.
Hinweis
Fügen Sie Ihrer Podfile die folgenden ML Kit-Bibliotheken hinzu:
pod 'GoogleMLKit/SegmentationSelfie', '8.0.0'Nachdem Sie die Pods Ihres Projekts installiert oder aktualisiert haben, öffnen Sie Ihr Xcode-Projekt mit der Datei „.
xcworkspace“. ML Kit wird in Xcode Version 13.2.1 oder höher unterstützt.
1. Segmentierer-Instanz 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.
Segmentierer-Optionen
Segmentierer-Modus
Der Segmenter funktioniert in zwei Modi. Wählen Sie den Modus aus, der zu Ihrem Anwendungsfall passt.
STREAM_MODE (default)
Dieser Modus ist für das Streamen von Frames aus Videos oder Kameras konzipiert. In diesem Modus verwendet der Segmentierer Ergebnisse aus vorherigen Frames, um genauere Segmentierungsergebnisse zurückzugeben.
SINGLE_IMAGE_MODE (default)
Dieser Modus ist für einzelne, nicht zusammenhängende Bilder konzipiert. In diesem Modus verarbeitet der Segmentierer jedes Bild unabhängig, ohne die Ergebnisse über mehrere Frames hinweg zu glätten.
Maske mit Rohgröße aktivieren
Fordert den Segmentierer auf, die Rohgrößenmaske zurückzugeben, die der Modellausgabe entspricht.
Die Größe der Rohmaske (z.B. 256 × 256) ist in der Regel kleiner als die Größe des Eingabebilds.
Wenn Sie diese Option nicht angeben, skaliert der Segmentierer die Rohmaske so, dass sie der Größe des Eingabebilds entspricht. Verwenden Sie diese Option, wenn Sie eine benutzerdefinierte Skalierungslogik anwenden möchten oder wenn für Ihren Anwendungsfall keine Skalierung erforderlich ist.
Geben Sie die Segmentierer-Optionen 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 schließlich eine Instanz von Segmenter ab. Übergeben Sie die von Ihnen angegebenen Optionen:
Swift
let segmenter = Segmenter.segmenter(options: options)
Objective-C
MLKSegmenter *segmenter = [MLKSegmenter segmenterWithOptions:options];
2. Eingabebild vorbereiten
Wenn Sie Selfies segmentieren möchten, führen Sie für jedes Bild oder jeden Frame des Videos die folgenden Schritte aus.
Wenn Sie den Stream-Modus aktiviert haben, müssen Sie VisionImage-Objekte aus CMSampleBuffers erstellen.
Erstellen Sie ein VisionImage-Objekt mit einem UIImage oder einem
CMSampleBuffer.
Wenn Sie ein UIImage verwenden, gehen Sie so vor:
- Erstellen Sie ein
VisionImage-Objekt mit demUIImage. Geben Sie die richtige.orientationan.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:
-
Geben Sie die Ausrichtung der Bilddaten im
CMSampleBufferan.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; } }
- Erstellen Sie ein
VisionImage-Objekt mit demCMSampleBuffer-Objekt 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 das VisionImage-Objekt an eine der Bildverarbeitungsfunktionen des Segmenter. Sie können entweder die asynchrone Methode process(image:) oder die synchrone Methode results(in:) verwenden.
So führen Sie die Segmentierung eines Selfie-Bilds synchron aus:
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 Selfie-Bilds asynchron aus:
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 abrufen:
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-Kurzanleitung.
Tipps zur Leistungsverbesserung
Die Qualität Ihrer Ergebnisse hängt von der Qualität des Eingabebilds ab:
- Damit ML Kit ein genaues Segmentierungsergebnis erzielen kann, sollte das Bild mindestens 256 × 256 Pixel groß sein.
- Wenn Sie die Selfie-Segmentierung in einer Echtzeitanwendung ausfü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 einer niedrigeren Auflösung aufnehmen. Beachten Sie jedoch die oben genannten Anforderungen an die Auflösung und sorgen Sie dafür, dass das Motiv so viel Platz wie möglich im Bild einnimmt.
- Eine schlechte Bildschärfe kann sich auch auf die Genauigkeit auswirken. Wenn Sie keine akzeptablen Ergebnisse erhalten, bitten Sie den Nutzer, das Bild noch einmal aufzunehmen.
Wenn Sie die Segmentierung in einer Echtzeitanwendung verwenden möchten, folgen Sie diesen Richtlinien, um die besten Frameraten zu erzielen:
- Verwenden Sie den Segmentierer-Modus
stream. - Nehmen Sie Bilder mit einer niedrigeren Auflösung auf. Beachten Sie jedoch auch die Anforderungen an die Bildabmessungen dieser API.
- Verwenden Sie für die Verarbeitung von Videoframes die synchrone API
results(in:)des Segmentierers. Rufen Sie diese Methode aus der Funktion AVCaptureVideoDataOutputSampleBufferDelegate's captureOutput(_, didOutput:from:) des AVCaptureVideoDataOutputSampleBufferDelegate auf, um synchron Ergebnisse aus dem angegebenen Videoframe zu erhalten. Setzen Sie AVCaptureVideoDataOutputs alwaysDiscardsLateVideoFrames auf „true“, um die Aufrufe des Segmentierers zu drosseln. Wenn ein neuer Videoframe verfügbar wird, während der Segmentierer ausgeführt wird, wird er verworfen. - Wenn Sie die Ausgabe des Segmentierers verwenden, um Grafiken auf das Eingabebild zu legen, rufen Sie zuerst das Ergebnis von ML Kit ab und rendern Sie dann das Bild und die Überlagerung in einem Schritt. So rendern Sie für jeden verarbeiteten Eingabeframe nur einmal auf der Anzeigefläche. Ein Beispiel finden Sie in den Klassen previewOverlayView und CameraViewController in der ML Kit-Kurzanleitung.