Guia de segmentação de imagens para iOS

A tarefa "Segmento de imagens" permite dividir imagens em regiões com base em categorias predefinidas e aplicar efeitos visuais, como o desfoque do plano de fundo. Estas instruções mostram como usar o Segmentador de imagens com apps para iOS.

O exemplo de código descrito nestas instruções está disponível no GitHub.

Confira esta tarefa em ação na demonstração da Web. Para mais informações sobre os recursos, modelos e opções de configuração desta tarefa, consulte a Visão geral.

Exemplo de código

O exemplo de código do MediaPipe Tasks contém uma implementação simples de um app de segmentação de imagens para iOS.

O exemplo implementa um segmento de imagens que gera máscaras de categoria. Ele usa a câmera em um dispositivo iOS físico para realizar a segmentação de imagens em um feed de câmera ao vivo ou em imagens e vídeos da galeria do dispositivo.

Você pode usar o app como ponto de partida para seu próprio app iOS ou se referir a ele ao modificar um app existente. O código de exemplo do segmentador de imagens está hospedado no GitHub.

Fazer o download do código

As instruções a seguir mostram como criar uma cópia local do código de exemplo usando a ferramenta de linha de comando git.

Para fazer o download do código de exemplo:

  1. Clone o repositório do Git usando o seguinte comando:

    git clone https://github.com/google-ai-edge/mediapipe-samples/
    
  2. Opcionalmente, configure sua instância do Git para usar o checkout esparso, para que você tenha apenas os arquivos do app de exemplo do Image Segmenter:

    cd mediapipe
    git sparse-checkout init --cone
    git sparse-checkout set examples/image_segmentation/ios/
    

Depois de criar uma versão local do código de exemplo, é possível instalar a biblioteca de tarefas do MediaPipe, abrir o projeto usando o Xcode e executar o app. Para instruções, consulte o Guia de configuração para iOS.

Principais componentes

Os arquivos a seguir contêm o código crucial para o exemplo de aplicativo Image Segmenter:

Configuração

Esta seção descreve as principais etapas para configurar seu ambiente de desenvolvimento e projetos de código para usar o Segmentador de imagens. Para informações gerais sobre como configurar seu ambiente de desenvolvimento para usar tarefas do MediaPipe, incluindo os requisitos de versão da plataforma, consulte o Guia de configuração para iOS.

Dependências

O Image Segmenter usa a biblioteca MediaPipeTasksVision, que precisa ser instalada usando o CocoaPods. A biblioteca é compatível com apps Swift e Objective-C e não requer nenhuma configuração específica da linguagem.

Para instruções sobre como instalar o CocoaPods no macOS, consulte o Guia de instalação do CocoaPods. Para instruções sobre como criar um Podfile com os pods necessários para seu app, consulte Como usar CocoaPods.

Adicione o pod MediaPipeTasksVision no Podfile usando o seguinte código:

target 'MyImageSegmenterApp' do
  use_frameworks!
  pod 'MediaPipeTasksVision'
end

Se o app incluir destinos de teste de unidade, consulte o Guia de configuração para iOS para mais informações sobre como configurar o Podfile.

Modelo

A tarefa do segmentador de imagem do MediaPipe exige um modelo treinado compatível com essa tarefa. Para mais informações sobre os modelos treinados disponíveis para o segmentador de imagens, consulte a seção de modelos da visão geral da tarefa.

Selecione e faça o download de um modelo e adicione-o ao diretório do projeto usando o Xcode. Para instruções sobre como adicionar arquivos ao projeto do Xcode, consulte Como gerenciar arquivos e pastas no projeto do Xcode.

Use a propriedade BaseOptions.modelAssetPath para especificar o caminho para o modelo no app bundle. Para conferir um exemplo de código, consulte a próxima seção.

Criar a tarefa

É possível criar a tarefa de segmentação de imagens chamando um dos inicializadores dela. O inicializador ImageSegmenter(options:) aceita valores para as opções de configuração.

Se você não precisar de um segmentador de imagens inicializado com opções de configuração personalizadas, use o inicializador ImageSegmenter(modelPath:) para criar um segmentador de imagens com as opções padrão. Para mais informações sobre as opções de configuração, consulte Visão geral da configuração.

A tarefa Segmentador de imagens é compatível com três tipos de dados de entrada: imagens estáticas, arquivos de vídeo e streams de vídeo ao vivo. Por padrão, ImageSegmenter(modelPath:) inicializa uma tarefa de imagens estáticas. Se você quiser que a tarefa seja inicializada para processar arquivos de vídeo ou transmissões de vídeo ao vivo, use ImageSegmenter(options:) para especificar o modo de execução do vídeo ou da transmissão ao vivo. O modo de transmissão ao vivo também exige a opção de configuração adicional imageSegmenterLiveStreamDelegate, que permite que o segmentador de imagens envie resultados de segmentação de imagem para o delegado de forma assíncrona.

Escolha a guia correspondente ao modo de execução para saber como criar a tarefa e executar a inferência.

Swift

Imagem

import MediaPipeTasksVision

let modelPath = Bundle.main.path(forResource: "model",
                                      ofType: "tflite")

let options = ImageSegmenterOptions()
options.baseOptions.modelAssetPath = modelPath
options.runningMode = .image
options.shouldOutputCategoryMask = true
options.shouldOutputConfidenceMasks = false

let imageSegmenter = try ImageSegmenter(options: options)
    

Vídeo

import MediaPipeTasksVision

let modelPath = Bundle.main.path(forResource: "model",
                                      ofType: "tflite")

let options = ImageSegmenterOptions()
options.baseOptions.modelAssetPath = modelPath
options.runningMode = .video
options.shouldOutputCategoryMask = true
options.shouldOutputConfidenceMasks = false

let imageSegmenter = try ImageSegmenter(options: options)
    

Transmissão ao vivo

import MediaPipeTasksVision

// Class that conforms to the `imageSegmenterLiveStreamDelegate` protocol and
// implements the method that the image segmenter calls once it finishes
// performing segmentation of each input frame.
class ImageSegmenterResultProcessor: NSObject, ImageSegmenterLiveStreamDelegate {

  func imageSegmenter(
    _ imageSegmenter: ImageSegmenter,
    didFinishSegmentation result: ImageSegmenterResult?,
    timestampInMilliseconds: Int,
    error: Error?) {

    // Process the image segmentation result or errors here.

  }
}

let modelPath = Bundle.main.path(forResource: "model",
                                      ofType: "tflite")

let options = ImageSegmenterOptions()
options.baseOptions.modelAssetPath = modelPath
options.runningMode = .liveStream
options.shouldOutputCategoryMask = true
options.shouldOutputConfidenceMasks = false

// Set `imageSegmenterLiveStreamDelegate` to the object of the class that
// confirms to the `ImageSegmenterLiveStreamDelegate` protocol.
let processor = ImageSegmenterResultProcessor()
options.imageSegmenterLiveStreamDelegate = processor

let imageSegmenter = try ImageSegmenter(options: options)
    

Objective-C

Imagem

@import MediaPipeTasksVision;

NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"model"
                                                      ofType:@"tflite"];

MPPImageSegmenterOptions *options = [[MPPImageSegmenterOptions alloc] init];
options.baseOptions.modelAssetPath = modelPath;
options.runningMode = MPPRunningModeImage;
options.shouldOutputCategoryMask = YES;
options.shouldOutputConfidenceMasks = NO;

MPPImageSegmenter *imageSegmenter =
  [[MPPImageSegmenter alloc] initWithOptions:options error:nil];
    

Vídeo

@import MediaPipeTasksVision;

NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"model"
                                                      ofType:@"tflite"];

MPPImageSegmenterOptions *options = [[MPPImageSegmenterOptions alloc] init];
options.baseOptions.modelAssetPath = modelPath;
options.runningMode = MPPRunningModeVideo;
options.shouldOutputCategoryMask = YES;
options.shouldOutputConfidenceMasks = NO;

MPPImageSegmenter *imageSegmenter =
  [[MPPImageSegmenter alloc] initWithOptions:options error:nil];
    

Transmissão ao vivo

@import MediaPipeTasksVision;

// Class that conforms to the `MPPImageSegmenterLiveStreamDelegate` protocol
// and implements the method that the image segmenter calls once it finishes
// performing segmentation of each input frame.

@interface APPImageSegmenterResultProcessor : NSObject 

@end

@implementation APPImageSegmenterResultProcessor

-   (void)imageSegmenter:(MPPImageSegmenter *)imageSegmenter
    didFinishSegmentationWithResult:(MPPImageSegmenterResult *)imageSegmenterResult
         timestampInMilliseconds:(NSInteger)timestampInMilliseconds
                           error:(NSError *)error {

    // Process the image segmentation result or errors here.

}

@end

NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"model"
                                                      ofType:@"tflite"];

MPPImageSegmenterOptions *options = [[MPPImageSegmenterOptions alloc] init];
options.baseOptions.modelAssetPath = modelPath;
options.runningMode = MPPRunningModeLiveStream;
options.shouldOutputCategoryMask = YES;
options.shouldOutputConfidenceMasks = NO;

// Set `imageSegmenterLiveStreamDelegate` to the object of the class that
// confirms to the `MPPImageSegmenterLiveStreamDelegate` protocol.
APPImageSegmenterResultProcessor *processor =
  [APPImageSegmenterResultProcessor new];
options.imageSegmenterLiveStreamDelegate = processor;

MPPImageSegmenter *imageSegmenter =
  [[MPPImageSegmenter alloc] initWithOptions:options error:nil];
    

A implementação do código de exemplo do segmentador de imagens permite que o usuário alterne entre os modos de processamento. A abordagem torna o código de criação da tarefa mais complicado e pode não ser apropriada para seu caso de uso.

Opções de configuração

Esta tarefa tem as seguintes opções de configuração para apps iOS:

Nome da opção Descrição Intervalo de valor Valor padrão
runningMode Define o modo de execução da tarefa. Há três modos:

IMAGEM: o modo para entradas de imagem única.

VÍDEO: o modo para quadros decodificados de um vídeo.

LIVE_STREAM: o modo de uma transmissão ao vivo de dados de entrada, como de uma câmera. Nesse modo, ImageSegmenterLiveStreamDelegate precisa ser definido como uma instância de uma classe que implementa o ImageSegmenterLiveStreamDelegate para receber os resultados de segmentação de forma assíncrona.
{RunningMode.image, RunningMode.video, RunningMode.liveStream} RunningMode.image
shouldOutputCategoryMask Se definido como True, a saída inclui uma máscara de segmentação como uma imagem uint8, em que cada valor de pixel indica o valor da categoria vencedora. {True, False} False
shouldOutputConfidenceMasks Se definido como True, a saída inclui uma máscara de segmentação como uma imagem de valor flutuante, em que cada valor flutuante representa o mapa de pontuação de confiança da categoria. {True, False} True
displayNamesLocale Define o idioma dos rótulos a serem usados nos nomes de exibição fornecidos nos metadados do modelo da tarefa, se disponíveis. O padrão é en para o inglês. É possível adicionar rótulos localizados aos metadados de um modelo personalizado usando a API TensorFlow Lite Metadata Writer. Código da localidade en
result_callback Define o listener de resultados para receber os resultados de segmentação de forma assíncrona quando o segmento de imagem está no modo LIVE_STREAM. Só pode ser usado quando o modo de execução está definido como LIVE_STREAM. N/A N/A

Quando o modo de execução está definido como LIVE_STREAM, o segmentador de imagens exige a opção de configuração imageSegmenterLiveStreamDelegate adicional, que permite que o segmentador de imagens forneça resultados de segmentação de imagens de forma assíncrona. O delegado precisa implementar o método imageSegmenter(_:didFinishSegmentation:timestampInMilliseconds:error:), que o Segmentador de imagem chama após processar os resultados da segmentação em cada frame.

Nome da opção Descrição Intervalo de valor Valor padrão
imageSegmenterLiveStreamDelegate Permite que o Image Segmenter receba os resultados da segmentação de imagens de forma assíncrona no modo de transmissão ao vivo. A classe que tem a instância definida para essa propriedade precisa implementar o método imageSegmenter(_:didFinishSegmentation:timestampInMilliseconds:error:). Não relevante Não definido

Preparar dados

É necessário converter a imagem ou o frame de entrada em um objeto MPImage antes de transmiti-lo ao segmentador de imagens. MPImage oferece suporte a diferentes tipos de formatos de imagem do iOS e pode usá-los em qualquer modo em execução para inferência. Para mais informações sobre MPImage, consulte a API MPImage.

Escolha um formato de imagem do iOS com base no seu caso de uso e no modo de execução exigido pelo aplicativo.MPImage aceita os formatos de imagem UIImage, CVPixelBuffer e CMSampleBuffer do iOS.

UIImage

O formato UIImage é adequado para os seguintes modos de execução:

  • Imagens: as imagens de um pacote de apps, galeria de usuários ou sistema de arquivos formatadas como UIImage podem ser convertidas em um objeto MPImage.

  • Vídeos: use o AVAssetImageGenerator para extrair frames de vídeo para o formato CGImage e os converter em imagens UIImage.

Swift

// Load an image on the user's device as an iOS `UIImage` object.

// Convert the `UIImage` object to a MediaPipe's Image object having the default
// orientation `UIImage.Orientation.up`.
let image = try MPImage(uiImage: image)
    

Objective-C

// Load an image on the user's device as an iOS `UIImage` object.

// Convert the `UIImage` object to a MediaPipe's Image object having the default
// orientation `UIImageOrientationUp`.
MPImage *image = [[MPPImage alloc] initWithUIImage:image error:nil];
    

O exemplo inicializa um MPImage com a orientação padrão UIImage.Orientation.Up. É possível inicializar uma MPImage com qualquer um dos valores UIImage.Orientation compatíveis. O Image Segmenter não oferece suporte a orientações espelhadas, como .upMirrored, .downMirrored, .leftMirrored e .rightMirrored.

Para mais informações sobre UIImage, consulte a documentação para desenvolvedores da Apple de UIImage (em inglês).

CVPixelBuffer

O formato CVPixelBuffer é adequado para aplicativos que geram frames e usam o framework CoreImage do iOS para processamento.

O formato CVPixelBuffer é adequado para os seguintes modos de execução:

  • Imagens: apps que geram imagens CVPixelBuffer após algum processamento usando o framework CoreImage do iOS podem ser enviados ao segmentador de imagens no modo de execução de imagens.

  • Vídeos: os frames de vídeo podem ser convertidos para o formato CVPixelBuffer para processamento e, em seguida, enviados para o segmentador de imagens no modo de vídeo.

  • Transmissão ao vivo: os apps que usam uma câmera do iOS para gerar frames podem ser convertidos para o formato CVPixelBuffer para processamento antes de serem enviados ao segmentador de imagens no modo de transmissão ao vivo.

Swift

// Obtain a CVPixelBuffer.

// Convert the `CVPixelBuffer` object to a MediaPipe's Image object having the default
// orientation `UIImage.Orientation.up`.
let image = try MPImage(pixelBuffer: pixelBuffer)
    

Objective-C

// Obtain a CVPixelBuffer.

// Convert the `CVPixelBuffer` object to a MediaPipe's Image object having the
// default orientation `UIImageOrientationUp`.
MPImage *image = [[MPPImage alloc] initWithUIImage:image error:nil];
    

Para mais informações sobre CVPixelBuffer, consulte a Documentação do desenvolvedor da Apple CVPixelBuffer (em inglês).

CMSampleBuffer

O formato CMSampleBuffer armazena amostras de mídia de um tipo uniforme e é adequado para o modo de execução de transmissões ao vivo. Os frames ao vivo das câmeras do iOS são enviados de forma assíncrona no formato CMSampleBuffer pelo AVCaptureVideoDataOutput do iOS.

Swift

// Obtain a CMSampleBuffer.

// Convert the `CMSampleBuffer` object to a MediaPipe's Image object having the default
// orientation `UIImage.Orientation.up`.
let image = try MPImage(sampleBuffer: sampleBuffer)
    

Objective-C

// Obtain a `CMSampleBuffer`.

// Convert the `CMSampleBuffer` object to a MediaPipe's Image object having the
// default orientation `UIImageOrientationUp`.
MPImage *image = [[MPPImage alloc] initWithSampleBuffer:sampleBuffer error:nil];
    

Para mais informações sobre CMSampleBuffer, consulte a documentação para desenvolvedores da Apple CMSampleBuffer (em inglês).

Executar a tarefa

Para executar o segmentador de imagens, use o método segment() específico para o modo de execução atribuído:

  • Imagem estática: segment(image:)
  • Vídeo: segment(videoFrame:timestampInMilliseconds:)
  • Transmissão ao vivo: segmentAsync(image:timestampInMilliseconds:)

Os exemplos de código a seguir mostram exemplos simples de como executar o segmentador de imagens nesses diferentes modos de execução:

Swift

Imagem

let result = try imageSegmenter.segment(image: image)
    

Vídeo

let result = try imageSegmenter.segment(
  videoFrame: image,
  timestampInMilliseconds: timestamp)
    

Transmissão ao vivo

try imageSegmenter.segmentAsync(
  image: image,
  timestampInMilliseconds: timestamp)
    

Objective-C

Imagem

MPPImageSegmenterResult *result =
  [imageSegmenter segmentImage:image error:nil];
    

Vídeo

MPPImageSegmenterResult *result =
  [imageSegmenter segmentVideoFrame:image
            timestampInMilliseconds:timestamp
                              error:nil];
    

Transmissão ao vivo

BOOL success =
  [imageSegmenter segmentAsyncImage:image
            timestampInMilliseconds:timestamp
                              error:nil];
    

O exemplo de código do segmentador de imagens mostra as implementações de cada um desses modos com mais detalhes segment(image:), segment(videoFrame:timestampInMilliseconds:) e segmentAsync(image:timestampInMilliseconds:).

Observe o seguinte:

  • Ao executar no modo de vídeo ou de transmissão ao vivo, você também precisa fornecer o carimbo de data/hora do frame de entrada para a tarefa do segmentador de imagens.

  • Quando executada no modo de imagem ou vídeo, a tarefa do segmentador de imagem bloqueia a linha de execução atual até que ela termine de processar a imagem ou o frame de entrada. Para evitar o bloqueio da linha de execução atual, execute o processamento em uma linha de execução em segundo plano usando os frameworks Dispatch ou NSOperation do iOS.

  • Quando executada no modo de transmissão ao vivo, a tarefa do segmentador de imagens é retornada imediatamente e não bloqueia a linha de execução atual. Ele invoca o método imageSegmenter(_:didFinishSegmentation:timestampInMilliseconds:error:) com o segmentador de imagens após o processamento de cada frame de entrada. O ImageSegmenter invoca esse método de forma assíncrona em uma fila de envio serial dedicada. Para mostrar os resultados na interface do usuário, envie os resultados para a fila principal depois de processá-los. Se a função segmentAsync for chamada quando a tarefa do segmentador de imagem estiver ocupada processando outro frame, o segmentador de imagem vai ignorar o novo frame de entrada.

Processar e mostrar resultados

Ao executar a inferência, a tarefa do segmentador de imagens retorna um objeto ImageSegmenterResult que contém os resultados da tarefa de segmentação. O conteúdo da saída depende do tipo de saída definido ao configurar a tarefa.

As imagens a seguir mostram uma visualização da saída da tarefa para uma máscara de valor de categoria. O intervalo da máscara de categoria é [0, 255], e cada valor de pixel representa o índice de categoria vencedor da saída do modelo. O índice da categoria vencedora tem a maior pontuação entre as categorias que o modelo pode reconhecer.

Saída da máscara de categoria e da imagem original. Imagem de origem do conjunto de dados Pascal VOC 2012.

O código de exemplo do segmentador de imagens demonstra como exibir os resultados do segmentador. Consulte o exemplo de código para mais detalhes.