A tarefa do MediaPipe Image Classifier permite que você faça a classificação de imagens. É possível usar essa tarefa para identificar o que uma imagem representa entre um conjunto de categorias definidas no tempo de treinamento. Estas instruções mostram como usar o Classificador de imagem com apps Android. O exemplo de código descrito nestas instruções está disponível no GitHub.
Para saber como essa tarefa funciona, confira a demonstração na Web. Para mais informações sobre os recursos, modelos e opções de configuração dessa 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 classificação de imagem para Android. O exemplo usa a câmera de um dispositivo Android físico para classificar objetos continuamente, além de usar imagens e vídeos da galeria para classificar objetos estaticamente.
Você pode usar o app como ponto de partida para seu próprio app Android ou consultá-lo ao modificar um app existente. O exemplo de código do Image Classifier está hospedado no GitHub.
Fazer o download do código
As instruções a seguir mostram como criar uma cópia local do exemplo de código usando a ferramenta de linha de comando git.
Para fazer o download do código de exemplo:
- Clone o repositório git usando o seguinte comando:
git clone https://github.com/google-ai-edge/mediapipe-samples
- Como opção, configure sua instância do Git para usar a finalização esparsa.
Assim, você terá apenas os arquivos do app de exemplo do Image Classifier:
cd mediapipe git sparse-checkout init --cone git sparse-checkout set examples/image_classification/android
Depois de criar uma versão local do exemplo de código, você pode importar o projeto para o Android Studio e executar o app. Para instruções, consulte o Guia de configuração para Android.
Principais componentes
Os arquivos a seguir contêm o código crucial para esse aplicativo de exemplo de classificação de imagens:
- ImageClassifierHelper.kt: inicializa o classificador de imagem, processa o modelo e delega a seleção.
- MainActivity.kt:
implementa o aplicativo, incluindo a chamada de
ImageClassificationHelper
eClassificationResultsAdapter
. - ClassificationResultsAdapter.kt: processa e formata os resultados.
Configuração
Nesta seção, descrevemos as principais etapas para configurar seu ambiente de desenvolvimento e projetos de código para usar o classificador de imagem. Para informações gerais sobre como configurar seu ambiente de desenvolvimento para usar tarefas do MediaPipe, incluindo requisitos de versão da plataforma, consulte o Guia de configuração para Android.
Dependências
O Image Classificador usa a biblioteca com.google.mediapipe:tasks-vision
. Adicione essa
dependência ao arquivo build.gradle
do seu
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 imagem do MediaPipe requer um modelo treinado que seja compatível com essa tarefa. Para mais informações sobre modelos treinados disponíveis para o classificador de imagem, consulte a visão geral da tarefa seção Modelos.
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. Falaremos sobre esse método no exemplo de código na próxima
seção.
No
código de exemplo do classificador de imagem,
o modelo é definido no arquivo
ImageClassifierHelper.kt
.
Criar a tarefa
Use a função createFromOptions
para criar a tarefa. A
função createFromOptions
aceita opções de configuração, incluindo o modo de
execução, a localidade dos nomes de exibição, o número máximo de resultados, o limite de confiança
e uma lista de permissões ou bloqueio de categorias. Para mais informações sobre as opções de configuração, consulte Visão geral da configuração.
A tarefa Classificador de imagem é compatível com três tipos de dados de entrada: imagens estáticas, arquivos de vídeo e streams de vídeo ao vivo. Ao criar a tarefa, especifique o modo de execução correspondente ao tipo de dados de entrada. Escolha a guia correspondente ao 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 de código de exemplo do Image Classifier 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. Veja 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: IMAGEM: o modo para entradas de imagem única. VÍDEO: é o modo para frames 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, 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 nos nomes de exibição fornecidos nos
metadados do modelo da tarefa, se disponíveis. O padrão é en para
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 |
maxResults |
Define o número máximo opcional de resultados da classificação com maior pontuação a serem retornados. Se < 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 flutuação | Não definido |
categoryAllowlist |
Define a lista opcional de nomes de categorias permitidos. Se não estiver vazio, os resultados da classificação com nome de categoria que não estiver nesse conjunto serão filtrados. Nomes de categorias duplicados ou desconhecidos são ignorados.
Essa opção é mutuamente exclusiva com categoryDenylist e usar
os dois resulta em erro. |
Qualquer string | Não definido |
categoryDenylist |
Define a lista opcional de nomes de categorias que não são permitidos. Se não estiver vazio, os resultados da classificação com um nome de categoria nesse conjunto serão filtrados. Nomes de categorias duplicados ou desconhecidos são ignorados. Essa opção é mutuamente exclusiva com categoryAllowlist e usar os dois resulta em erro. |
Qualquer string | Não definido |
resultListener |
Define o listener de resultado para receber os resultados da classificação
de forma assíncrona quando o classificador de imagem estiver no modo de transmissão
ao vivo. Só pode ser usado quando o modo de corrida está definido como LIVE_STREAM |
N/A | Não definido |
errorListener |
Define um listener de erro opcional. | N/A | Não definido |
preparar os dados
O Image Classificador funciona com imagens, arquivos de vídeo e streaming de vídeo ao vivo. Ela processa o pré-processamento de entrada de dados, incluindo redimensionamento, rotação e normalização de valor.
É necessário converter a imagem de entrada ou o frame em um
objeto com.google.mediapipe.framework.image.MPImage
antes de transmiti-lo ao
classificador de imagem.
Imagem
import com.google.mediapipe.framework.image.BitmapImageBuilder; import com.google.mediapipe.framework.image.MPImage; // Load an image on the user’s device as a Bitmap object using BitmapFactory. // Convert an Android’s Bitmap object to a MediaPipe’s 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 video’s metadata, load the METADATA_KEY_DURATION and // METADATA_KEY_VIDEO_FRAME_COUNT value. You’ll need them // to calculate the timestamp of each frame later. // Loop through the video and load each frame as a Bitmap object. // Convert the Android’s Bitmap object to a MediaPipe’s 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 CameraX’s ImageAnalysis to continuously receive frames // from the device’s camera. Configure it to output frames in RGBA_8888 // format to match with what is required by the model. // For each Android’s ImageProxy object received from the ImageAnalysis, // extract the encapsulated Android’s Image object and convert it to // a MediaPipe’s Image object. android.media.Image mediaImage = imageProxy.getImage() Image mpImage = new MediaImageBuilder(mediaImage).build();
No
código de exemplo do Image Classifier, a preparação de dados é processada no
arquivo
ImageClassifierHelper.kt
.
Executar a tarefa
É possível chamar 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 de entrada ou no frame.
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 imagem.
- Quando executada no modo de imagem ou vídeo, a tarefa do Classificador 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 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 imagem não bloqueia
a linha de execução atual, mas retorna imediatamente. Ele invocará o listener de resultados 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 imagem estiver ocupada processando outro frame, a tarefa ignora o novo frame de entrada.
No
código de exemplo do classificador de imagem, as funções classify
são definidas no
arquivo
ImageClassifierHelper.kt
.
Gerenciar e exibir resultados
Ao executar a inferência, a tarefa do classificador de imagem retorna um objeto ImageClassifierResult
que contém a lista de categorias possíveis para os objetos na imagem de entrada ou no frame.
Confira abaixo 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 Bird Classifier em:
No
código de exemplo do classificador de imagem, 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]
}
}
}