A tarefa MediaPipe Image Embedder permite converter dados de imagem em uma representação numérica para realizar tarefas de processamento de imagens relacionadas a ML, como comparar similaridade de duas imagens. Estas instruções mostram como usar o Incorporador de imagens com apps Android.
Para mais informações sobre 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 incorporador de imagem para Android. O exemplo usa a câmera de um dispositivo Android físico para incorporar imagens continuamente e também 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 consultá-lo ao modificar um aplicativo existente. O exemplo de código do incorporador de imagens está hospedado GitHub.
Fazer o download do código
As instruções a seguir mostram como criar uma cópia local do exemplo. 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
- Opcionalmente, configure sua instância git para usar a finalização esparsa. Assim, você terá
apenas os arquivos do app de exemplo do incorporador de imagens:
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 no Android Studio e executar o app. Para obter instruções, consulte o Guia de configuração do Android.
Principais componentes
Os arquivos a seguir contêm o código crucial para este exemplo de incorporador de imagens aplicativo:
- ImageEmbedderHelper.kt: inicializa o incorporador de imagem e processa o modelo e o delegado
- 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 incorporador de imagens. Para informações gerais sobre como configurar sua ambiente de desenvolvimento para usar tarefas do MediaPipe, incluindo a versão da plataforma consulte o Guia de configuração do Android.
Dependências
O incorporador de imagens usa a biblioteca com.google.mediapipe:tasks-vision
. Adicionar
dependência do 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 MediaPipe Image Embedder exige um modelo treinado que seja compatível com esse tarefa. Para mais informações sobre os modelos treinados disponíveis para o incorporador de imagens, consulte na seção de visão geral da tarefa Modelos.
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
. Na
código de exemplo, o modelo é definido na função setupImageEmbedder()
na
ImageEmbedderHelper.kt
arquivo:
Use o método BaseOptions.Builder.setModelAssetPath()
para especificar o caminho.
usados pelo modelo. Esse método é mencionado no exemplo de código nos próximos
nesta seção.
Criar a tarefa
Use a função createFromOptions
para criar a tarefa. A
A função createFromOptions
aceita opções de configuração para definir o incorporador
. Para mais informações sobre as opções de configuração, consulte Configuração
Visão geral.
A tarefa Incorporador 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. Você precisa especificar o modo de corrida correspondente o tipo de dados de entrada ao criar a tarefa. Escolha a guia correspondente ao seu tipo de dados de entrada para ver 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);
O exemplo de implementação de código permite que o usuário alterne entre o processamento
dois modos. A abordagem torna o código de criação da tarefa mais complicado e pode não ser
apropriados para seu caso de uso. Confira esse código
função setupImageEmbedder()
na
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. Existem 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 transmissão ao vivo da entrada dados de uma câmera, por exemplo. Neste modo, resultListener deve ser chamado para configurar um listener e receber resultados de forma assíncrona. |
{IMAGE, VIDEO, LIVE_STREAM } |
IMAGE |
l2_normalize |
Define se o vetor de atributo retornado deve ser normalizado com a norma L2. Use essa opção somente se o modelo ainda não tiver um L2_NORMALIZATION Op. do TFLite. Na maioria dos casos, esse já é o caso e Assim, a normalização L2 é alcançada por meio da inferência do TFLite sem a necessidade para essa opção. | Boolean |
False |
quantize |
Se o embedding retornado deve ser quantizado em bytes por meio de com a quantização escalar. Os embeddings são implicitamente definidos como unidade-norma e portanto, qualquer dimensão terá um valor em [-1.0, 1.0]. Usar a opção l2_normalize, se esse não for o caso. | Boolean |
False |
resultListener |
Define o listener de resultados para receber os resultados de embedding.
de forma assíncrona quando o incorporador de imagens está na transmissão ao vivo
modo 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 dados
O incorporador de imagens funciona com imagens, arquivos de vídeo e streaming de vídeo ao vivo. A tarefa lida com o pré-processamento de entrada de dados, incluindo redimensionamento, rotação e valor. normalização.
Você precisa converter a imagem ou frame de entrada
com.google.mediapipe.framework.image.MPImage
antes de transmiti-lo ao
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, a preparação dos dados é tratada na ImageEmbedderHelper.kt .
Executar a tarefa
Você pode chamar a função embed
correspondente ao modo de corrida para acionar
ou inferências. A API Image Embedder retorna os vetores de embedding para a entrada
imagem ou frame.
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 nos modos de vídeo ou de transmissão ao vivo, você também precisa forneça o carimbo de data/hora do frame de entrada para a tarefa Incorporador de imagens.
- Quando executada no modo de imagem ou vídeo, a tarefa Incorporador de imagens bloquear a linha de execução atual até que ela termine de processar a imagem de entrada ou frame. Para evitar o bloqueio da linha de execução atual, execute o processamento em um linha de execução em segundo plano.
- Quando executada no modo de transmissão ao vivo, a tarefa "Incorporador de imagens" não bloqueia
thread atual, mas retorna imediatamente. Ele vai invocar seu resultado
com o resultado da detecção sempre que ele terminar de processar um erro.
frame de entrada. Se a função
embedAsync
for chamada quando o incorporador de imagens estiver ocupada processando outro frame, a tarefa ignora o novo frame de entrada.
No código de exemplo, a função embed
é definida no
ImageEmbedderHelper.kt
.
Gerenciar e exibir resultados
Ao executar a inferência, a tarefa do incorporador de imagens retorna um ImageEmbedderResult
.
objeto que contém uma lista de embeddings (ponto flutuante ou
quantificada por escalar) para a imagem de entrada.
Confira abaixo 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 pela incorporação da seguinte imagem:
É possível comparar a semelhança de dois embeddings usando o
função ImageEmbedder.cosineSimilarity
. Confira o código a seguir
exemplo.
// Compute cosine similarity.
double similarity = ImageEmbedder.cosineSimilarity(
result.embeddingResult().embeddings().get(0),
otherResult.embeddingResult().embeddings().get(0));