Guia de segmentação de imagens para Android

A tarefa do segmentador de imagens do MediaPipe permite dividir imagens em regiões com base em categorias predefinidas para aplicar efeitos visuais, como desfoque de plano de fundo. Estas instruções mostram como usar o Segmentador de imagens com apps Android. O exemplo de código descrito nestas instruções está disponível no GitHub. 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 duas implementações simples de um app de segmentação de imagens para Android:

Os exemplos usam a câmera em um dispositivo Android físico para realizar a segmentação de imagens em um feed de câmera ao vivo. Você também pode escolher imagens e vídeos na galeria do dispositivo. Você pode usar os apps como ponto de partida para o seu próprio app Android ou consultá-los ao modificar um app existente. O código de exemplo do segmentador de imagens está hospedado no GitHub.

As seções a seguir se referem ao app Image Segmenter com uma máscara de categoria.

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/android
    

Depois de criar uma versão local do código de exemplo, você pode importar o projeto para o Android Studio e executar o app. Para ver instruções, consulte o Guia de configuração para Android.

Principais componentes

Os arquivos a seguir contêm o código crucial para este exemplo de aplicativo de segmentação de imagens:

  • ImageSegmenterHelper.kt: inicializa a tarefa do segmentador de imagens e processa a seleção do modelo e do delegado.
  • CameraFragment.kt: fornece a interface do usuário e o código de controle de uma câmera.
  • GalleryFragment.kt: fornece a interface do usuário e o código de controle para selecionar arquivos de imagem e vídeo.
  • OverlayView.kt: processa e formata os resultados da segmentação.

Configuração

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

Dependências

O segmentador de imagens usa a biblioteca com.google.mediapipe:tasks-vision. Adicione essa dependência ao arquivo build.gradle do projeto de desenvolvimento de apps Android. Importe as dependências necessárias com o seguinte código:

dependencies {
    ...
    implementation 'com.google.mediapipe:tasks-vision:latest.release'
}

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 Image Segmenter, consulte a seção "Modelos" da visão geral da tarefa.

Selecione e faça o download do modelo e armazene-o no diretório do projeto:

<dev-project-root>/src/main/assets

Use o método BaseOptions.Builder.setModelAssetPath() para especificar o caminho usado pelo modelo. Esse método é mencionado no exemplo de código na próxima seção.

No código de exemplo do segmentador de imagens, o modelo é definido na classe ImageSegmenterHelper.kt na função setupImageSegmenter().

Criar a tarefa

Você pode usar a função createFromOptions para criar a tarefa. A função createFromOptions aceita opções de configuração, incluindo tipos de saída de máscara. Para mais informações sobre a configuração de tarefas, consulte Opções de configuração.

A tarefa do segmentador de imagens oferece suporte aos seguintes tipos de dados de entrada: imagens estáticas, arquivos de vídeo e transmissões de vídeo ao vivo. É necessário especificar o modo de execução correspondente ao tipo de dados de entrada ao criar a tarefa. Escolha a guia do tipo de dados de entrada para saber como criar essa tarefa.

Imagem

ImageSegmenterOptions options =
  ImageSegmenterOptions.builder()
    .setBaseOptions(
      BaseOptions.builder().setModelAssetPath("model.tflite").build())
    .setRunningMode(RunningMode.IMAGE)
    .setOutputCategoryMask(true)
    .setOutputConfidenceMasks(false)
    .build();
imagesegmenter = ImageSegmenter.createFromOptions(context, options);
    

Vídeo

ImageSegmenterOptions options =
  ImageSegmenterOptions.builder()
    .setBaseOptions(
      BaseOptions.builder().setModelAssetPath("model.tflite").build())
    .setRunningMode(RunningMode.VIDEO)
    .setOutputCategoryMask(true)
    .setOutputConfidenceMasks(false)
    .build();
imagesegmenter = ImageSegmenter.createFromOptions(context, options);
    

Transmissão ao vivo

ImageSegmenterOptions options =
  ImageSegmenterOptions.builder()
    .setBaseOptions(
      BaseOptions.builder().setModelAssetPath("model.tflite").build())
    .setRunningMode(RunningMode.LIVE_STREAM)
    .setOutputCategoryMask(true)
    .setOutputConfidenceMasks(false)
    .setResultListener((result, inputImage) -> {
         // Process the segmentation result here.
    })
    .setErrorListener((result, inputImage) -> {
         // Process the segmentation errors here.
    })
    .build()
imagesegmenter = ImageSegmenter.createFromOptions(context, options)
    

A implementação do código de exemplo do segmentador de imagens permite que o usuário alterne entre os modos de processamento. Essa abordagem torna o código de criação de tarefas mais complicado e pode não ser adequado para seu caso de uso. Você pode conferir esse código na classe ImageSegmenterHelper pela função setupImageSegmenter().

Opções de configuração

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

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:

IMAGE: 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, o resultListener precisa ser chamado para configurar um listener para receber resultados de forma assíncrona.
{IMAGE, VIDEO, LIVE_STREAM} IMAGE
outputCategoryMask 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
outputConfidenceMasks 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 para os nomes de exibição fornecidos nos metadados do modelo da tarefa, se disponível. O padrão é en para o inglês. É possível adicionar rótulos localizados aos metadados de um modelo personalizado usando a API Writer de metadados do TensorFlow Lite. Código de localidade en
resultListener Define o listener de resultado para receber os resultados da segmentação de forma assíncrona quando o segmentador de imagens está no modo LIVE_STREAM. Só pode ser usado quando o modo de execução está definido como LIVE_STREAM. N/A N/A
errorListener Define um listener de erro opcional. N/A Não definido

Preparar dados

O Segmentador de imagens funciona com imagens, arquivos de vídeo e vídeos de transmissão ao vivo. A tarefa processa a entrada de dados, incluindo redimensionamento, rotação e normalização de valores.

É necessário converter a imagem ou o frame de entrada em um objeto com.google.mediapipe.framework.image.MPImage antes de transmiti-lo ao segmentador de imagens.

Imagem

import com.google.mediapipe.framework.image.BitmapImageBuilder;
import com.google.mediapipe.framework.image.MPImage;

// Load an image on the users device as a Bitmap object using BitmapFactory.

// Convert an Androids Bitmap object to a MediaPipes Image object.
Image mpImage = new BitmapImageBuilder(bitmap).build();
    

Vídeo

import com.google.mediapipe.framework.image.BitmapImageBuilder;
import com.google.mediapipe.framework.image.MPImage;

// Load a video file on the user's device using MediaMetadataRetriever

// From the videos metadata, load the METADATA_KEY_DURATION and
// METADATA_KEY_VIDEO_FRAME_COUNT value. Youll need them
// to calculate the timestamp of each frame later.

// Loop through the video and load each frame as a Bitmap object.

// Convert the Androids Bitmap object to a MediaPipes Image object.
Image mpImage = new BitmapImageBuilder(frame).build();
    

Transmissão ao vivo

import com.google.mediapipe.framework.image.MediaImageBuilder;
import com.google.mediapipe.framework.image.MPImage;

// Create a CameraXs ImageAnalysis to continuously receive frames
// from the devices camera. Configure it to output frames in RGBA_8888
// format to match with what is required by the model.

// For each Androids ImageProxy object received from the ImageAnalysis,
// extract the encapsulated Androids Image object and convert it to
// a MediaPipes Image object.
android.media.Image mediaImage = imageProxy.getImage()
Image mpImage = new MediaImageBuilder(mediaImage).build();
    

No código de exemplo do segmentador de imagens, o preparo de dados é processado na classe ImageSegmenterHelper pela função segmentLiveStreamFrame().

Executar a tarefa

Você chama uma função segment diferente com base no modo de execução que está usando. A função Image Segmenter retorna as regiões de segmento identificadas na imagem ou frame de entrada.

Imagem

ImageSegmenterResult segmenterResult = imagesegmenter.segment(image);
    

Vídeo

// Calculate the timestamp in milliseconds of the current frame.
long frame_timestamp_ms = 1000 * video_duration * frame_index / frame_count;

// Run inference on the frame.
ImageSegmenterResult segmenterResult =
    imagesegmenter.segmentForVideo(image, frameTimestampMs);
    

Transmissão ao vivo

// Run inference on the frame. The segmentations results will be available via
// the `resultListener` provided in the `ImageSegmenterOptions` when the image
// segmenter was created.
imagesegmenter.segmentAsync(image, frameTimestampMs);
    

Observe o seguinte:

  • Ao executar no modo de vídeo ou de transmissão ao vivo, também é necessário 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 de entrada ou o frame. Para evitar o bloqueio da interface do usuário, execute o processamento em uma linha de execução em segundo plano.
  • Quando executada no modo de transmissão ao vivo, a tarefa do segmentador de imagens não bloqueia a linha de execução atual, mas retorna imediatamente. Ele vai invocar o listener de resultado com o resultado da detecção sempre que terminar de processar um frame de entrada. Se a função segmentAsync for chamada quando a tarefa do segmentador de imagens estiver ocupada processando outro frame, a tarefa vai ignorar o novo frame de entrada.

No código de exemplo do segmentador de imagens, as funções segment são definidas no arquivo ImageSegmenterHelper.kt.

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 outputType que você definiu ao configurar a tarefa.

As seções a seguir mostram exemplos dos dados de saída desta tarefa:

Confiança da categoria

As imagens a seguir mostram uma visualização da saída da tarefa para uma máscara de confiança de categoria. A saída da máscara de confiança contém valores flutuantes entre [0, 1].

Duas meninas andando a cavalo e uma menina andando ao lado do cavalo A máscara de imagem que descreve a forma das meninas e do cavalo da foto anterior. A metade esquerda do contorno da imagem é capturada, mas a metade direita não é

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

Valor da categoria

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.

Duas meninas andando a cavalo e uma menina andando ao lado do cavalo A máscara de imagem que descreve a forma das meninas e do cavalo da imagem anterior. A forma das três meninas e do cavalo está mascarada corretamente

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