ML Kit fournit un SDK optimisé pour la segmentation des selfies. Les composants du segmenter de selfies sont liés statiquement à votre application au moment de la compilation. La taille de votre application augmentera de 24 Mo maximum, et la latence de l'API peut varier de 7 ms à 12 ms environ en fonction de la taille de l'image d'entrée, comme mesuré sur l'iPhone X.
Essayer
- Testez l'application exemple pour voir un exemple d'utilisation de cette API.
Avant de commencer
Incluez les bibliothèques ML Kit suivantes dans votre fichier Podfile :
pod 'GoogleMLKit/SegmentationSelfie', '8.0.0'
Après avoir installé ou mis à jour les pods de votre projet, ouvrez votre projet Xcode à l'aide de son fichier .
xcworkspace
. ML Kit est compatible avec Xcode version 13.2.1 ou ultérieure.
1. Créer une instance de Segmenter
Pour effectuer une segmentation sur une image de selfie, créez d'abord une instance de Segmenter
avec SelfieSegmenterOptions
et spécifiez éventuellement les paramètres de segmentation.
Options de segmentation
Mode Segmenteur
Segmenter
fonctionne dans deux modes. Assurez-vous de choisir celui qui correspond à votre cas d'utilisation.
STREAM_MODE (default)
Ce mode est conçu pour diffuser des images à partir d'une vidéo ou d'une caméra. Dans ce mode, le segmenter exploite les résultats des frames précédents pour renvoyer des résultats de segmentation plus fluides.
SINGLE_IMAGE_MODE (default)
Ce mode est conçu pour les images individuelles sans lien entre elles. Dans ce mode, le segmenter traite chaque image indépendamment, sans lisser les images.
Activer le masque de taille brute
Demande au segmenter de renvoyer le masque de taille brute qui correspond à la taille de sortie du modèle.
La taille du masque brut (par exemple, 256 x 256) est généralement inférieure à celle de l'image d'entrée.
Sans spécifier cette option, le segmenter redimensionnera le masque brut pour qu'il corresponde à la taille de l'image d'entrée. Envisagez d'utiliser cette option si vous souhaitez appliquer une logique de remise à l'échelle personnalisée ou si la remise à l'échelle n'est pas nécessaire pour votre cas d'utilisation.
Spécifiez les options du segmenter :
Swift
let options = SelfieSegmenterOptions() options.segmenterMode = .singleImage options.shouldEnableRawSizeMask = true
Objective-C
MLKSelfieSegmenterOptions *options = [[MLKSelfieSegmenterOptions alloc] init]; options.segmenterMode = MLKSegmenterModeSingleImage; options.shouldEnableRawSizeMask = YES;
Enfin, obtenez une instance de Segmenter
. Transmettez les options que vous avez spécifiées :
Swift
let segmenter = Segmenter.segmenter(options: options)
Objective-C
MLKSegmenter *segmenter = [MLKSegmenter segmenterWithOptions:options];
2. Préparer l'image d'entrée
Pour segmenter les selfies, procédez comme suit pour chaque image ou frame vidéo.
Si vous avez activé le mode flux, vous devez créer des objets VisionImage
à partir de CMSampleBuffer
.
Créez un objet VisionImage
à l'aide d'un UIImage
ou d'un CMSampleBuffer
.
Si vous utilisez un UIImage
, procédez comme suit :
- Créez un objet
VisionImage
avecUIImage
. Veillez à spécifier le.orientation
approprié.Swift
let image = VisionImage(image: UIImage) visionImage.orientation = image.imageOrientation
Objective-C
MLKVisionImage *visionImage = [[MLKVisionImage alloc] initWithImage:image]; visionImage.orientation = image.imageOrientation;
Si vous utilisez un CMSampleBuffer
, procédez comme suit :
-
Spécifiez l'orientation des données d'image contenues dans
CMSampleBuffer
.Pour obtenir l'orientation de l'image :
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; } }
- Créez un objet
VisionImage
à l'aide de l'objetCMSampleBuffer
et de l'orientation :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. Traiter l'image
Transmettez l'objet VisionImage
à l'une des méthodes de traitement d'image de Segmenter
. Vous pouvez utiliser la méthode asynchrone process(image:)
ou la méthode synchrone results(in:)
.
Pour effectuer la segmentation d'une image de selfie de manière synchrone :
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.
Pour effectuer la segmentation d'une image de selfie de manière asynchrone :
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. Obtenir le masque de segmentation
Vous pouvez obtenir le résultat de la segmentation comme suit :
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); }
Pour obtenir un exemple complet d'utilisation des résultats de la segmentation, veuillez consulter l'exemple de démarrage rapide de ML Kit.
Conseils pour améliorer les performances
La qualité de vos résultats dépend de celle de l'image d'entrée :
- Pour que ML Kit obtienne un résultat de segmentation précis, l'image doit faire au moins 256 x 256 pixels.
- Si vous effectuez une segmentation de selfies dans une application en temps réel, vous pouvez également tenir compte des dimensions globales des images d'entrée. Les images plus petites peuvent être traitées plus rapidement. Pour réduire la latence, capturez des images à des résolutions plus faibles, mais gardez à l'esprit les exigences de résolution ci-dessus et assurez-vous que le sujet occupe la plus grande partie possible de l'image.
- Une mise au point médiocre de l'image peut également avoir un impact sur la précision. Si vous n'obtenez pas de résultats acceptables, demandez à l'utilisateur de reprendre la photo.
Si vous souhaitez utiliser la segmentation dans une application en temps réel, suivez ces consignes pour obtenir les meilleures fréquences d'images :
- Utilisez le mode segmenter
stream
. - Envisagez de prendre des photos à une résolution inférieure. Toutefois, gardez également à l'esprit les exigences de cette API concernant les dimensions des images.
- Pour traiter les images vidéo, utilisez l'API synchrone
results(in:)
du segmenter. Appelez cette méthode à partir de la fonction captureOutput(_, didOutput:from:) de AVCaptureVideoDataOutputSampleBufferDelegate pour obtenir de manière synchrone les résultats de la frame vidéo donnée. Définissez alwaysDiscardsLateVideoFrames de AVCaptureVideoDataOutput sur "true" pour limiter les appels au segmenter. Si une nouvelle image vidéo devient disponible pendant l'exécution du segmenter, elle sera supprimée. - Si vous utilisez la sortie du segmenter pour superposer des éléments graphiques sur l'image d'entrée, obtenez d'abord le résultat de ML Kit, puis affichez l'image et la superposition en une seule étape. Vous n'avez ainsi besoin d'effectuer le rendu sur la surface d'affichage qu'une seule fois pour chaque frame d'entrée traité. Pour obtenir un exemple, consultez les classes previewOverlayView et CameraViewController dans l'exemple de démarrage rapide de ML Kit.