A tarefa do MediaPipe Image Embedder permite converter dados de imagem em uma representação numérica para realizar tarefas de processamento de imagens relacionadas ao ML, como comparar a semelhança de duas imagens. Estas instruções mostram como usar o Image Embedder com apps Android.
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 Image Embedder para Android. O exemplo usa a câmera em um dispositivo Android físico para incorporar imagens continuamente e também pode executar o incorporador em arquivos de imagem armazenados no dispositivo.
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 Image Embedder 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:
- Clone o repositório do Git usando o seguinte comando:
git clone https://github.com/google-ai-edge/mediapipe-samples
- 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 Embedder:
cd mediapipe git sparse-checkout init --cone git sparse-checkout set examples/image_embedder/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 este aplicativo de exemplo de incorporação de imagens:
- ImageEmbedderHelper.kt: inicializa o incorporador de imagens e processa a seleção de modelo e delegação.
- MainActivity.kt: implementa o aplicativo e monta os componentes da interface do usuário.
Configuração
Esta seção descreve as principais etapas para configurar seu ambiente de desenvolvimento e projetos de código para usar o Embedder de imagens. Para informações gerais sobre como configurar seu ambiente de desenvolvimento para usar as tarefas do MediaPipe, incluindo os requisitos de versão da plataforma, consulte o Guia de configuração para Android.
Dependências
O Image Embedder 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 Image Embedder requer um modelo treinado compatível com essa tarefa. Para mais informações sobre os modelos treinados disponíveis para o Gerador de embeddings de imagem, 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
Especifique o caminho do modelo no parâmetro ModelAssetPath
. No
código de exemplo, o modelo é definido na função setupImageEmbedder()
no
arquivo
ImageEmbedderHelper.kt:
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.
Criar a tarefa
Você pode usar a função createFromOptions
para criar a tarefa. A
função createFromOptions
aceita opções de configuração para definir as opções
de incorporação. Para mais informações sobre as opções de configuração, consulte Visão geral da
configuração.
A tarefa Image Embedder 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
ImageEmbedderOptions options = ImageEmbedderOptions.builder() .setBaseOptions( BaseOptions.builder().setModelAssetPath("model.tflite").build()) .setQuantize(true) .setRunningMode(RunningMode.IMAGE) .build(); imageEmbedder = ImageEmbedder.createFromOptions(context, options);
Vídeo
ImageEmbedderOptions options = ImageEmbedderOptions.builder() .setBaseOptions( BaseOptions.builder().setModelAssetPath("model.tflite").build()) .setQuantize(true) .setRunningMode(RunningMode.VIDEO) .build(); imageEmbedder = ImageEmbedder.createFromOptions(context, options);
Transmissão ao vivo
ImageEmbedderOptions options = ImageEmbedderOptions.builder() .setBaseOptions( BaseOptions.builder().setModelAssetPath("model.tflite").build()) .setQuantize(true) .setRunningMode(RunningMode.LIVE_STREAM) .setResultListener((result, inputImage) -> { // Process the embedding result here. }) .build(); imageEmbedder = ImageEmbedder.createFromOptions(context, options);
A implementação do código de exemplo 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. Esse código está na função
setupImageEmbedder()
no arquivo
ImageEmbedderHelper.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 |
l2_normalize |
Se o vetor de recursos retornado vai ser normalizado com a norma L2. Use essa opção somente se o modelo ainda não tiver uma operação TFLite L2_NORMALIZATION nativa. Na maioria dos casos, isso já acontece e a normalização L2 é alcançada pela inferência do TFLite sem a necessidade dessa opção. | Boolean |
False |
quantize |
Indica se o embedding retornado precisa ser quantizado em bytes por meio de quantização escalar. As inclusões são implicitamente consideradas como unidade-norm e, portanto, qualquer dimensão tem garantia de ter um valor em [-1,0, 1,0]. Use a opção l2_normalize se não for esse o caso. | Boolean |
False |
resultListener |
Define o listener de resultado para receber os resultados de incorporação
de forma assíncrona quando o incorporador de imagem 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 Embedder de imagens funciona com imagens, arquivos de vídeo e vídeo 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 à
tarefa do incorporador de imagens.
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, o preparo de dados é processado no arquivo ImageEmbedderHelper.kt.
Executar a tarefa
É possível chamar a função embed
correspondente ao modo de execução para acionar
inferências. A API Image Embedder retorna os vetores de incorporação para a imagem
ou o frame de entrada.
Imagem
ImageEmbedderResult embedderResult = imageEmbedder.embed(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. ImageEmbedderResult embedderResult = imageEmbedder.embedForVideo(image, frameTimestampMs);
Transmissão ao vivo
// Run inference on the frame. The embedding results will be available // via the `resultListener` provided in the `ImageEmbedderOptions` when // the image embedder was created. imageEmbedder.embedAsync(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 incorporador de imagens.
- Quando executada no modo de imagem ou vídeo, a tarefa de incorporação 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 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 incorporador 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
embedAsync
for chamada quando a tarefa do incorporador de imagens estiver ocupada processando outro frame, a tarefa vai ignorar o novo frame de entrada.
No código de exemplo, a função embed
é definida no arquivo
ImageEmbedderHelper.kt.
Processar e mostrar resultados
Ao executar a inferência, a tarefa Image Embedder retorna um objeto ImageEmbedderResult
que contém uma lista de embeddings (ponto flutuante ou
quantização escalar) para a imagem de entrada.
Confira a seguir um exemplo dos dados de saída desta tarefa:
ImageEmbedderResult:
Embedding #0 (sole embedding head):
float_embedding: {0.0, 0.0, ..., 0.0, 1.0, 0.0, 0.0, 2.0}
head_index: 0
Esse resultado foi obtido ao incorporar a seguinte imagem:
É possível comparar a semelhança de duas embeddings usando a
função ImageEmbedder.cosineSimilarity
. Confira o exemplo de código a seguir:
// Compute cosine similarity.
double similarity = ImageEmbedder.cosineSimilarity(
result.embeddingResult().embeddings().get(0),
otherResult.embeddingResult().embeddings().get(0));