Guia de detecção de objetos para Android

A tarefa do detector de objetos permite detectar a presença e a localização de várias classes de objetos. Por exemplo, um detector de objetos pode localizar cães em uma imagem. Estas instruções mostram como usar a tarefa do detector de objetos no Android. O exemplo de código descrito nestas instruções está disponível no GitHub. Confira esta demonstração na Web para conferir essa tarefa em ação. 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 código de exemplo do MediaPipe Tasks é uma implementação simples de um app de detecção de objetos para Android. O exemplo usa a câmera em um dispositivo Android físico para detectar objetos continuamente e também pode usar imagens e vídeos da galeria do dispositivo para detectar objetos de forma estática.

Você pode usar o app como ponto de partida para seu próprio app Android ou se referir a ele ao modificar um app existente. O código de exemplo do Detector de objetos 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 Detector de objetos:
    cd mediapipe
    git sparse-checkout init --cone
    git sparse-checkout set examples/object_detection/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 abaixo contêm o código crucial para o aplicativo de exemplo do Detector de objetos:

Configuração

Esta seção descreve as principais etapas para configurar seu ambiente de desenvolvimento e projetos de código para usar o Detector de objetos. 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 detector de objetos 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 MediaPipe Object Detector requer um modelo treinado compatível com essa tarefa. Para mais informações sobre os modelos treinados disponíveis para o Detector de objetos, 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. Para conferir um exemplo de código, consulte a próxima seção.

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 modo de execução, localidade de nomes de exibição, número máximo de resultados, limite de confiança, lista de permissões e de bloqueio de categorias. Se uma opção de configuração não for especificada, o valor padrão será usado. Para mais informações sobre as opções de configuração, consulte Visão geral da configuração.

A tarefa do detector de objetos oferece suporte a três 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 correspondente ao seu tipo de dados de entrada para saber como criar a tarefa e executar a inferência.

Imagem

ObjectDetectorOptions options =
  ObjectDetectorOptions.builder()
    .setBaseOptions(BaseOptions.builder().setModelAssetPath(‘model.tflite’).build())
    .setRunningMode(RunningMode.IMAGE)
    .setMaxResults(5)
    .build();
objectDetector = ObjectDetector.createFromOptions(context, options);
    

Vídeo

ObjectDetectorOptions options =
  ObjectDetectorOptions.builder()
    .setBaseOptions(BaseOptions.builder().setModelAssetPath(‘model.tflite’).build())
    .setRunningMode(RunningMode.VIDEO)
    .setMaxResults(5)
    .build();
objectDetector = ObjectDetector.createFromOptions(context, options);
    

Transmissão ao vivo

ObjectDetectorOptions options =
  ObjectDetectorOptions.builder()
    .setBaseOptions(BaseOptions.builder().setModelAssetPath(model.tflite).build())
    .setRunningMode(RunningMode.LIVE_STREAM)
    .setMaxResults(5)
    .setResultListener((result, inputImage) -> {
      // Process the detection result here.
    })
    .setErrorListener((result, inputImage) -> {
      // Process the classification errors here.
    })
   .build();
objectDetector = ObjectDetector.createFromOptions(context, options);
    

A implementação do código de exemplo do Detector de objetos permite que o usuário alterne entre 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 função setupObjectDetector() da classe ObjectDetectorHelper.

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
displayNamesLocales 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
maxResults Define o número máximo opcional de resultados de detecção com a maior pontuação a serem retornados. Qualquer número positivo -1 (todos os resultados são retornados)
scoreThreshold Define o limite de pontuação de previsão que substitui o fornecido nos metadados do modelo (se houver). Resultados abaixo desse valor são rejeitados. Qualquer ponto flutuante Não definido
categoryAllowlist Define a lista opcional de nomes de categorias permitidos. Se não estiver vazio, os resultados de detecção cujo nome da categoria não estiver neste conjunto serão filtrados. Nomes de categorias duplicados ou desconhecidos são ignorados. Essa opção é mutuamente exclusiva com categoryDenylist, e o uso de ambas resulta em um erro. Qualquer string Não definido
categoryDenylist Define a lista opcional de nomes de categorias não permitidos. Se não estiver vazio, os resultados de detecção cujo nome de categoria estiver neste conjunto serão filtrados. Nomes de categorias duplicados ou desconhecidos são ignorados. Essa opção é mutuamente exclusiva de categoryAllowlist, e o uso das duas resulta em um erro. Qualquer string Não definido
resultListener Define o listener de resultados para receber os resultados da detecção de forma assíncrona quando o detector de objetos está no modo de transmissão ao vivo. Só é possível usar essa opção quando você define o modo de execução como LIVE_STREAM. Não relevante Não definido

Preparar dados

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

Os exemplos a seguir explicam e mostram como preparar dados para processamento para cada um dos tipos de dados disponíveis:

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 values. Use these values
// 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()
MPImage mpImage = new MediaImageBuilder(mediaImage).build();
    

No código de exemplo do Detector de objetos, o preparo de dados é processado na classe ObjectDetectorHelper nas funções detectImage(), detectVideoFile() e detectLivestreamFrame().

Executar a tarefa

Dependendo do tipo de dados com que você está trabalhando, use o método ObjectDetector.detect...() específico para esse tipo de dados. Use detect() para imagens individuais, detectForVideo() para frames em arquivos de vídeo e detectAsync() para transmissões de vídeo. Ao realizar detecções em uma stream de vídeo, execute as detecções em uma linha de execução separada para evitar o bloqueio da linha de execução da interface do usuário.

Os exemplos de código a seguir mostram exemplos simples de como executar o Detector de objetos nesses diferentes modos de dados:

Imagem

ObjectDetectorResult detectionResult = objectDetector.detect(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.
ObjectDetectorResult detectionResult =
    objectDetector.detectForVideo(image, frameTimestampMs);
    

Transmissão ao vivo

// Run inference on the frame. The detection results will be available
// via the `resultListener` provided in the `ObjectDetectorOptions` when
// the object detector was created.
objectDetector.detectAsync(image, frameTimestampMs);
    

O exemplo de código do Detector de objetos mostra as implementações de cada um desses modos com mais detalhes detect(), detectVideoFile() e detectAsync(). O código de exemplo permite que o usuário alterne entre modos de processamento que podem não ser necessários para seu caso de uso.

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 detector de objetos.
  • Quando executada no modo de imagem ou vídeo, a tarefa do detector de objetos 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 linha de execução atual, execute o processamento em uma linha de execução em segundo plano.
  • Quando executada no modo de transmissão ao vivo, a tarefa do detector de objetos 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 de detecção for chamada quando a tarefa do Detector de objetos estiver ocupada processando outro frame, o novo frame de entrada será ignorado.

Processar e mostrar resultados

Ao executar a inferência, a tarefa do detector de objetos retorna um objeto ObjectDetectorResult que descreve os objetos encontrados na imagem de entrada.

Confira a seguir um exemplo dos dados de saída desta tarefa:

ObjectDetectorResult:
 Detection #0:
  Box: (x: 355, y: 133, w: 190, h: 206)
  Categories:
   index       : 17
   score       : 0.73828
   class name  : dog
 Detection #1:
  Box: (x: 103, y: 15, w: 138, h: 369)
  Categories:
   index       : 17
   score       : 0.73047
   class name  : dog

A imagem a seguir mostra uma visualização da saída da tarefa:

Dois cães destacados com caixas delimitadoras

O código de exemplo do Detector de objetos demonstra como mostrar os resultados de detecção retornados pela tarefa. Consulte a classe OverlayView para mais detalhes.