El Kit de AA proporciona un SDK optimizado para la segmentación de selfies. Los recursos del Segmentador de selfies se vinculan estáticamente a tu app durante el tiempo de compilación. Esto aumentará el tamaño de tu app hasta 24 MB, y la latencia de la API puede variar de ~7 ms a ~12 ms, según el tamaño de la imagen de entrada, según las mediciones de iPhone X.
Probar
- Prueba la app de ejemplo para ver un ejemplo de uso de esta API.
Antes de comenzar
Incluye las siguientes bibliotecas de ML Kit en tu Podfile:
pod 'GoogleMLKit/SegmentationSelfie', '3.2.0'
Después de instalar o actualizar los Pods de tu proyecto, abre el proyecto de Xcode a través de su archivo .
xcworkspace
. El Kit de AA es compatible con Xcode 13.2.1 o versiones posteriores.
1. Crear una instancia de Segmenter
Para realizar la segmentación en una imagen selfie, primero crea una instancia de Segmenter
con SelfieSegmenterOptions
y, opcionalmente, especifica la configuración de la segmentación.
Opciones del segmentador
Modo de segmentación
Segmenter
funciona en dos modos. Asegúrate de elegir la que coincida con tu caso de uso.
STREAM_MODE (default)
Este modo está diseñado para transmitir fotogramas de video o cámara. En este modo, el segmentador aprovechará los resultados de los fotogramas anteriores para devolver resultados de segmentación más fluidos.
SINGLE_IMAGE_MODE (default)
Este modo está diseñado para imágenes individuales que no están relacionadas. En este modo, el segmentador procesará cada imagen de manera independiente, sin suavizar los marcos.
Habilitar máscara de tamaño sin procesar
Solicita al segmentador que devuelva la máscara de tamaño sin procesar que coincide con el tamaño de salida del modelo.
El tamaño de máscara sin procesar (p.ej., 256 x 256) suele ser menor que el tamaño de la imagen de entrada.
Si no se especifica esta opción, el segmento cambiará la escala de la máscara sin procesar para que coincida con el tamaño de la imagen de entrada. Considera usar esta opción si deseas aplicar una lógica de reescalamiento personalizada o si no es necesario hacerlo en tu caso de uso.
Especifica las opciones del segmento:
Swift
let options = SelfieSegmenterOptions() options.segmenterMode = .singleImage options.shouldEnableRawSizeMask = true
Objective-C
MLKSelfieSegmenterOptions *options = [[MLKSelfieSegmenterOptions alloc] init]; options.segmenterMode = MLKSegmenterModeSingleImage; options.shouldEnableRawSizeMask = YES;
Por último, obtén una instancia de Segmenter
. Pasa las opciones que especificaste:
Swift
let segmenter = Segmenter.segmenter(options: options)
Objective-C
MLKSegmenter *segmenter = [MLKSegmenter segmenterWithOptions:options];
2. Prepara la imagen de entrada
Si quieres segmentar selfies, haz lo siguiente para cada imagen o fotograma de video.
Si habilitaste el modo de transmisión, debes crear objetos VisionImage
a partir de
CMSampleBuffer
Crea un objeto VisionImage
con un objeto UIImage
o
CMSampleBuffer
Si usas un UIImage
, sigue estos pasos:
- Crea un objeto
VisionImage
conUIImage
. Asegúrate de especificar el.orientation
correcto.Swift
let image = VisionImage(image: UIImage) visionImage.orientation = image.imageOrientation
Objective-C
MLKVisionImage *visionImage = [[MLKVisionImage alloc] initWithImage:image]; visionImage.orientation = image.imageOrientation;
Si usas un CMSampleBuffer
, sigue estos pasos:
-
Especificar la orientación de los datos de imagen que se incluyen en la
CMSampleBuffer
Para obtener la orientación de la imagen, haz lo siguiente:
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; } }
- Crea un objeto
VisionImage
con el elemento ObjetoCMSampleBuffer
y orientación: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. Procesa la imagen
Pasa el objeto VisionImage
a uno de los métodos de procesamiento de imágenes de Segmenter
. Puedes usar el método asíncrono process(image:)
o el método síncrono results(in:)
.
Para realizar una segmentación en una imagen selfie de forma síncrona, haz lo siguiente:
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.
Para segmentar una imagen selfie de forma asíncrona, haz lo siguiente:
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. Obtén la máscara de segmentación
Puedes obtener el resultado de la segmentación de la siguiente manera:
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); }
Para obtener un ejemplo completo de cómo utilizar los resultados de segmentación, consulta el Muestra de la guía de inicio rápido del Kit de AA.
Sugerencias para mejorar el rendimiento
La calidad de los resultados depende de la calidad de la imagen de entrada:
- Para que el Kit de AA obtenga un resultado de segmentación preciso, la imagen debe tener al menos 256 × 256 píxeles.
- Si realizas la segmentación de selfie en una aplicación en tiempo real, también deberías considerar las dimensiones generales de las imágenes de entrada. Las imágenes más pequeñas se pueden procesar más rápido. Por lo tanto, para reducir la latencia, captura imágenes con resoluciones más bajas, pero ten en cuenta los requisitos de resolución anteriores y asegúrate de que el objeto ocupe la mayor parte posible de la imagen.
- Un enfoque de imagen deficiente también puede afectar la precisión. Si no obtienes resultados aceptables, solicita al usuario que vuelva a capturar la imagen.
Si quieres usar la segmentación en una aplicación en tiempo real, sigue estos lineamientos para lograr las mejores velocidades de fotogramas:
- Usa el modo de segmentación
stream
. - Intenta capturar imágenes con una resolución más baja. Sin embargo, también ten en cuenta los requisitos de dimensiones de imágenes de esta API.
- Para procesar fotogramas de video, usa la API síncrona
results(in:)
del segmentador. Llama a este método desde la función captureOutput(_, didOutput:from:) de AVCaptureVideoDataOutputSampleBufferDelegate para obtener resultados de un fotograma determinado de video de forma síncrona. Mantén el valor alwaysDiscardsLateVideoFrames de AVCaptureVideoDataOutput para limitar las llamadas al segmentador. Si hay un fotograma de video nuevo disponible mientras se ejecuta el segmento, se descartará. - Si usas el resultado del segmento para superponer gráficos en la imagen de entrada, primero debes obtener el resultado del ML Kit y, luego, renderizar la imagen y la superposición en un solo paso. De esta manera, procesas la superficie de visualización solo una vez por cada fotograma de entrada procesado. Consulta las clases previewOverlayView y CameraViewController en la muestra de inicio rápido del Kit de AA para ver un ejemplo.