O Kit de ML oferece um SDK otimizado para segmentação de selfies. Os recursos do segmentador de selfies são vinculados estaticamente ao app no tempo de build. Isso aumenta o tamanho do app em até 24 MB, e a latência da API pode variar de ~7 ms a ~12 ms, dependendo do tamanho da imagem de entrada, conforme medido no iPhone X.
Faça um teste
- Teste o app de exemplo para conferir um exemplo de uso dessa API.
Antes de começar
Inclua as seguintes bibliotecas do Kit de ML no seu Podfile:
pod 'GoogleMLKit/SegmentationSelfie', '8.0.0'Depois de instalar ou atualizar os pods do projeto, abra o projeto do Xcode usando o .
xcworkspace. O Kit de ML é compatível com a versão 13.2.1 ou mais recente do Xcode.
1. Criar uma instância do segmentador
Para realizar a segmentação em uma imagem de selfie, primeiro crie uma instância de Segmenter com SelfieSegmenterOptions e, opcionalmente, especifique as configurações de segmentação.
Opções do segmentador
Modo do segmentador
O Segmenter opera em dois modos. Escolha o que corresponde ao seu caso de uso.
STREAM_MODE (default)
Esse modo foi projetado para transmitir frames de vídeo ou câmera. Nesse modo, o segmentador aproveita os resultados de frames anteriores para retornar resultados de segmentação mais suaves.
SINGLE_IMAGE_MODE (default)
Esse modo foi projetado para imagens únicas não relacionadas. Nesse modo, o segmentador processa cada imagem de forma independente, sem suavização nos frames.
Ativar máscara de tamanho bruto
Solicita que o segmentador retorne a máscara de tamanho bruto que corresponde ao tamanho da saída do modelo.
O tamanho da máscara bruta (por exemplo, 256 x 256) geralmente é menor que o tamanho da imagem de entrada.
Sem especificar essa opção, o segmentador vai redimensionar a máscara bruta para corresponder ao tamanho da imagem de entrada. Considere usar essa opção se você quiser aplicar uma lógica de redimensionamento personalizada ou se o redimensionamento não for necessário para seu caso de uso.
Especifique as opções do segmentador:
Swift
let options = SelfieSegmenterOptions() options.segmenterMode = .singleImage options.shouldEnableRawSizeMask = true
Objective-C
MLKSelfieSegmenterOptions *options = [[MLKSelfieSegmenterOptions alloc] init]; options.segmenterMode = MLKSegmenterModeSingleImage; options.shouldEnableRawSizeMask = YES;
Por fim, receba uma instância de Segmenter. Transmita as opções especificadas:
Swift
let segmenter = Segmenter.segmenter(options: options)
Objective-C
MLKSegmenter *segmenter = [MLKSegmenter segmenterWithOptions:options];
2. Preparar a imagem de entrada
Para segmentar selfies, faça o seguinte para cada imagem ou frame de vídeo.
Se você ativou o modo de transmissão, crie objetos VisionImage de CMSampleBuffers.
Crie um VisionImage objeto usando um UIImage ou um
CMSampleBuffer.
Se você usar um UIImage, siga estas etapas:
- Crie um
VisionImageobjeto com oUIImage. Especifique o.orientationcorreto.Swift
let image = VisionImage(image: UIImage) visionImage.orientation = image.imageOrientation
Objective-C
MLKVisionImage *visionImage = [[MLKVisionImage alloc] initWithImage:image]; visionImage.orientation = image.imageOrientation;
Se você usar um CMSampleBuffer, siga estas etapas:
-
Especifique a orientação dos dados da imagem contidos no
CMSampleBuffer.Para receber a orientação da imagem:
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; } }
- Crie um
VisionImageobjeto usando oCMSampleBufferobjeto e a orientação: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. Processar a imagem
Transmita o objeto VisionImage para um dos métodos de processamento de imagem do Segmenter. Você pode usar o método assíncrono process(image:) ou o método síncrono results(in:).
Para realizar a segmentação em uma imagem de selfie de forma síncrona:
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 realizar a segmentação em uma imagem de selfie de forma assíncrona:
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. Receber a máscara de segmentação
Você pode receber o resultado da segmentação da seguinte maneira:
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 conferir um exemplo completo de como usar os resultados da segmentação, consulte a amostra de início rápido do Kit de ML.
Dicas para melhorar a performance
A qualidade dos resultados depende da qualidade da imagem de entrada:
- Para que o Kit de ML receba um resultado de segmentação preciso, a imagem precisa ter pelo menos 256 x 256 pixels.
- Se você realizar a segmentação de selfies em um aplicativo em tempo real, considere as dimensões gerais das imagens de entrada. Imagens menores podem ser processadas mais rapidamente. Portanto, para reduzir a latência, capture imagens em resoluções mais baixas, mas tenha em mente os requisitos de resolução acima e garanta que o assunto ocupe o máximo possível da imagem.
- O foco ruim da imagem também pode afetar a precisão. Se você não receber resultados aceitáveis, peça ao usuário para recapturar a imagem.
Se você quiser usar a segmentação em um aplicativo em tempo real, siga estas diretrizes para alcançar as melhores taxas de frames:
- Use o modo de segmentador
stream. - Considere capturar imagens em uma resolução mais baixa. No entanto, tenha em mente os requisitos de dimensão da imagem dessa API.
- Para processar frames de vídeo, use a API síncrona
results(in:)do segmentador. Chame esse método da função captureOutput(_, didOutput:from:) do AVCaptureVideoDataOutputSampleBufferDelegate para receber resultados de forma síncrona do frame de vídeo fornecido. Mantenha AVCaptureVideoDataOutput's alwaysDiscardsLateVideoFrames como verdadeiro para limitar as chamadas ao segmentador. Se um novo frame de vídeo ficar disponível enquanto o segmentador estiver em execução, ele será descartado. - Se você estiver usando a saída do segmentador para sobrepor elementos gráficos na imagem de entrada, primeiro acesse o resultado do Kit de ML e, em seguida, renderize a imagem e a sobreposição em uma única etapa. Ao fazer isso, você renderiza a superfície de exibição apenas uma vez para cada frame de entrada processado. Consulte as classes previewOverlayView e CameraViewController na amostra de início rápido do Kit de ML para conferir um exemplo.