Guia de classificação de imagens para Android

A tarefa do classificador de imagens do MediaPipe permite realizar a classificação de imagens. Você pode usar essa tarefa para identificar o que uma imagem representa entre um conjunto de categorias definidas no momento do treinamento. Estas instruções mostram como usar o classificador de imagens com apps Android. O exemplo de código descrito nestas instruções está disponível no GitHub.

Confira esta tarefa em ação na demonstração na 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 código de exemplo do MediaPipe Tasks é uma implementação simples de um app classificador de imagens para Android. O exemplo usa a câmera em um dispositivo Android físico para classificar objetos continuamente e também pode usar imagens e vídeos da galeria do dispositivo para classificar 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 Classificador 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 Classificador de imagens:
    cd mediapipe
    git sparse-checkout init --cone
    git sparse-checkout set examples/image_classification/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 aplicativo de exemplo de classificação de imagens:

Configuração

Esta seção descreve as principais etapas para configurar seu ambiente de desenvolvimento e projetos de código para usar o Classificador de imagens. 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 classificador 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 classificador de imagens do MediaPipe exige um modelo treinado compatível com essa tarefa. Para mais informações sobre os modelos treinados disponíveis para o Classificador de imagens, 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 classificador de imagens, o modelo é definido no arquivo ImageClassifierHelper.kt.

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 e uma lista de permissões ou denegações de categoria. Para mais informações sobre as opções de configuração, consulte Visão geral da configuração.

A tarefa do classificador de imagens 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

ImageClassifierOptions options =
  ImageClassifierOptions.builder()
    .setBaseOptions(
      BaseOptions.builder().setModelAssetPath("model.tflite").build())
    .setRunningMode(RunningMode.IMAGE)
    .setMaxResults(5)
    .build();
imageClassifier = ImageClassifier.createFromOptions(context, options);
    

Vídeo

ImageClassifierOptions options =
  ImageClassifierOptions.builder()
    .setBaseOptions(
      BaseOptions.builder().setModelAssetPath("model.tflite").build())
    .setRunningMode(RunningMode.VIDEO)
    .setMaxResults(5)
    .build();
imageClassifier = ImageClassifier.createFromOptions(context, options);
    

Transmissão ao vivo

ImageClassifierOptions options =
  ImageClassifierOptions.builder()
    .setBaseOptions(
      BaseOptions.builder().setModelAssetPath("model.tflite").build())
    .setRunningMode(RunningMode.LIVE_STREAM)
    .setMaxResults(5)
    .setResultListener((result, inputImage) -> {
         // Process the classification result here.
    })
    .setErrorListener((result, inputImage) -> {
         // Process the classification errors here.
    })
    .build()
imageClassifier = ImageClassifier.createFromOptions(context, options)
    

A implementação do código de exemplo do classificador de imagens 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 setupImageClassifier() do arquivo ImageClassifierHelper.kt.

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
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
maxResults Define o número máximo opcional de resultados de classificação com a maior pontuação a serem retornados. Se for < 0, todos os resultados disponíveis serão retornados. Qualquer número positivo -1
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 classificação cujo nome de 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 classificaçã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 de classificação de forma assíncrona quando o classificador de imagens está no modo de transmissão ao vivo. Só pode ser usado quando o modo de execução está definido como LIVE_STREAM. N/A Não definido
errorListener Define um listener de erro opcional. N/A Não definido

Preparar dados

O classificador 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 classificador 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 classificador de imagens, o preparo de dados é processado no arquivo ImageClassifierHelper.kt.

Executar a tarefa

Chame a função classify correspondente ao modo de execução para acionar inferências. A API Image Classifier retorna as categorias possíveis para o objeto na imagem ou frame de entrada.

Imagem

ImageClassifierResult classifierResult = imageClassifier.classify(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.
ImageClassifierResult classifierResult =
    imageClassifier.classifyForVideo(image, frameTimestampMs);
    

Transmissão ao vivo

// Run inference on the frame. The classifications results will be available 
// via the `resultListener` provided in the `ImageClassifierOptions` when 
// the image classifier was created.
imageClassifier.classifyAsync(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 classificador de imagens.
  • Quando executada no modo de imagem ou vídeo, a tarefa do classificador de imagens 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 classificador 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 classifyAsync for chamada quando a tarefa do classificador de imagens estiver ocupada processando outro frame, a tarefa vai ignorar o novo frame de entrada.

No código de exemplo do classificador de imagens, as funções classify são definidas no arquivo ImageClassifierHelper.kt.

Processar e mostrar resultados

Ao executar a inferência, a tarefa do classificador de imagens retorna um objeto ImageClassifierResult que contém a lista de categorias possíveis para os objetos na imagem ou no frame de entrada.

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

ImageClassifierResult:
 Classifications #0 (single classification head):
  head index: 0
  category #0:
   category name: "/m/01bwb9"
   display name: "Passer domesticus"
   score: 0.91406
   index: 671
  category #1:
   category name: "/m/01bwbt"
   display name: "Passer montanus"
   score: 0.00391
   index: 670

Esse resultado foi obtido executando o classificador de pássaros em:

Foto em close de um pardal

No código de exemplo do classificador de imagens, a classe ClassificationResultsAdapter no arquivo ClassificationResultsAdapter.kt processa os resultados:

fun updateResults(imageClassifierResult: ImageClassifierResult? = null) {
    categories = MutableList(adapterSize) { null }
    if (imageClassifierResult != null) {
        val sortedCategories = imageClassifierResult.classificationResult()
            .classifications()[0].categories().sortedBy { it.index() }
        val min = kotlin.math.min(sortedCategories.size, categories.size)
        for (i in 0 until min) {
            categories[i] = sortedCategories[i]
        }
    }
}