ML Kit fornisce un SDK ottimizzato per la segmentazione dei selfie. Gli asset di Selfie Segmenter sono collegati in modo statico alla tua app in fase di compilazione. Le dimensioni dell'app aumenteranno fino a 24 MB e la latenza dell'API può variare da circa 7 ms a circa 12 ms a seconda delle dimensioni dell'immagine di input, misurate su iPhone X.
Prova
- Prova l'app di esempio per vedere un esempio di utilizzo di questa API.
Prima di iniziare
Includi le seguenti librerie ML Kit nel tuo Podfile:
pod 'GoogleMLKit/SegmentationSelfie', '7.0.0'
Dopo aver installato o aggiornato i pod del progetto, apri il progetto Xcode utilizzando il file .
xcworkspace
. ML Kit è supportato nella versione Xcode 13.2.1 o successive.
1. Crea un'istanza di Segmenter
Per eseguire la segmentazione su un'immagine selfie, crea prima un'istanza di Segmenter
con SelfieSegmenterOptions
e, facoltativamente, specifica le impostazioni di segmentazione.
Opzioni del segmentatore
Modalità Segmenter
Segmenter
opera in due modalità. Assicurati di scegliere quello più adatto al tuo caso d'uso.
STREAM_MODE (default)
Questa modalità è progettata per lo streaming di fotogrammi da video o fotocamera. In questa modalità, lo segmentatore sfrutta i risultati dei frame precedenti per restituire risultati di segmentazione più fluidi.
SINGLE_IMAGE_MODE (default)
Questa modalità è progettata per singole immagini non correlate. In questa modalità, lo segmentatore elabora ogni immagine in modo indipendente, senza applicare l'appiattimento ai frame.
Attiva maschera dimensioni non elaborate
Chiede al segmentatore di restituire la maschera delle dimensioni non elaborate che corrisponde alle dimensioni di output del modello.
Le dimensioni della maschera non elaborata (ad es. 256 x 256) sono in genere inferiori alle dimensioni dell'immagine di input.
Se non specifichi questa opzione, lo strumento di segmentazione ridimensionerà la maschera non elaborata in base alle dimensioni dell'immagine di input. Valuta la possibilità di utilizzare questa opzione se vuoi applicare una logica di ricoscalatura personalizzata o se la ricoscalatura non è necessaria per il tuo caso d'uso.
Specifica le opzioni del segmentatore:
let options = SelfieSegmenterOptions() options.segmenterMode = .singleImage options.shouldEnableRawSizeMask = true
MLKSelfieSegmenterOptions *options = [[MLKSelfieSegmenterOptions alloc] init]; options.segmenterMode = MLKSegmenterModeSingleImage; options.shouldEnableRawSizeMask = YES;
Infine, ottieni un'istanza di Segmenter
. Passa le opzioni specificate:
let segmenter = Segmenter.segmenter(options: options)
MLKSegmenter *segmenter = [MLKSegmenter segmenterWithOptions:options];
2. Prepara l'immagine di input
Per segmentare i selfie, svolgi le seguenti operazioni per ogni immagine o fotogramma del video.
Se hai attivato la modalità di streaming, devi creare oggetti VisionImage
da
CMSampleBuffer
.
Crea un oggetto VisionImage
utilizzando un UIImage
o un
CMSampleBuffer
.
Se utilizzi un UIImage
, segui questi passaggi:
- Crea un oggetto
VisionImage
conUIImage
. Assicurati di specificare il valore.orientation
corretto.let image = VisionImage(image: UIImage) visionImage.orientation = image.imageOrientation
MLKVisionImage *visionImage = [[MLKVisionImage alloc] initWithImage:image]; visionImage.orientation = image.imageOrientation;
Se utilizzi un CMSampleBuffer
, segui questi passaggi:
-
Specifica l'orientamento dei dati dell'immagine contenuti in
CMSampleBuffer
.Per ottenere l'orientamento dell'immagine:
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 } }
- (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; } }
- Crea un oggetto
VisionImage
utilizzando l'orientamento e l'oggettoCMSampleBuffer
:let image = VisionImage(buffer: sampleBuffer) image.orientation = imageOrientation( deviceOrientation: UIDevice.current.orientation, cameraPosition: cameraPosition)
MLKVisionImage *image = [[MLKVisionImage alloc] initWithBuffer:sampleBuffer]; image.orientation = [self imageOrientationFromDeviceOrientation:UIDevice.currentDevice.orientation cameraPosition:cameraPosition];
3. Elabora l'immagine
Passa l'oggetto VisionImage
a uno dei metodi di elaborazione delle immagini di Segmenter
. Puoi utilizzare il metodo asincrono process(image:)
o il metodo sincrono results(in:)
.
Per eseguire la segmentazione in modo sincrono su un'immagine selfie:
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.
NSError *error; MLKSegmentationMask *mask = [segmenter resultsInImage:image error:&error]; if (error != nil) { // Error. return; } // Success. Get a segmentation mask here.
Per eseguire la segmentazione di un'immagine di selfie in modo asincrono:
segmenter.process(image) { mask, error in guard error == nil else { // Error. return } // Success. Get a segmentation mask here.
[segmenter processImage:image completion:^(MLKSegmentationMask * _Nullable mask, NSError * _Nullable error) { if (error != nil) { // Error. return; } // Success. Get a segmentation mask here. }];
4. Ottenere la maschera di segmentazione
Puoi ottenere il risultato della segmentazione come segue:
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 }
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); }
Per un esempio completo di come utilizzare i risultati della segmentazione, consulta l'esempio di Quickstart di ML Kit.
Suggerimenti per migliorare il rendimento
La qualità dei risultati dipende dalla qualità dell'immagine di input:
- Affinché ML Kit ottenga un risultato di segmentazione accurato, l'immagine deve avere almeno 256 x 256 pixel.
- Se esegui la segmentazione dei selfie in un'applicazione in tempo reale, ti consigliamo di prendere in considerazione anche le dimensioni complessive delle immagini di input. Le immagini più piccole possono essere elaborate più velocemente, quindi per ridurre la latenza, acquisisci le immagini a risoluzioni inferiori, ma tieni presente i requisiti di risoluzione sopra indicati e assicurati che il soggetto occupi il maggior spazio possibile dell'immagine.
- Anche la scarsa messa a fuoco delle immagini può influire sull'accuratezza. Se non ottieni risultati accettabili, chiedi all'utente di acquisire di nuovo l'immagine.
Se vuoi utilizzare la segmentazione in un'applicazione in tempo reale, segui queste linee guida per ottenere le frequenze frame migliori:
- Utilizza la modalità di segmentazione
stream
. - Valuta la possibilità di acquisire le immagini a una risoluzione inferiore. Tuttavia, tieni presente anche i requisiti relativi alle dimensioni delle immagini di questa API.
- Per l'elaborazione dei frame video, utilizza l'API sincrona
results(in:)
del segmentatore. Chiama questo metodo dalla funzione captureOutput(_, didOutput:from:) di AVCaptureVideoDataOutputSampleBufferDelegate per ottenere in modo sincrono i risultati dal frame video specificato. Mantieni alwaysDiscardsLateVideoFrames di AVCaptureVideoDataOutput impostato su true per limitare le chiamate al segmentatore. Se un nuovo frame video diventa disponibile durante l'esecuzione del segmentatore, verrà ignorato. - Se utilizzi l'output del segmentatore per sovrapporre la grafica all'immagine di input, ottieni prima il risultato da ML Kit, quindi esegui il rendering dell'immagine e del overlay in un unico passaggio. In questo modo, esegui il rendering sulla superficie di visualizzazione una sola volta per ogni frame di input elaborato. Per un esempio, consulta le classi previewOverlayView e CameraViewController nell'esempio di avvio rapido di ML Kit.