Análise de imagem

O caso de uso de análise de imagens oferece ao app uma imagem acessível pela CPU para realizar processamento de imagens, visão computacional ou inferências de aprendizado de máquina. O aplicativo implementa um método analyze() executado em cada frame.

Implementação

As imagens são processadas pela transmissão de um executor em que a análise da imagem é executada e de um parâmetro ImageAnalysis.Analyzer para o método setAnalyzer(). Apenas um analisador pode ser registrado por vez: o registro de um novo analisador substitui o existente.

O exemplo de código neste tópico mostra como fazer isso e como vincular o caso de uso de análise de imagens e um caso de uso de visualização ao LifecycleOwner. Para ler sobre a criação de casos de usos de visualização, consulte Implementar uma visualização.

A análise de imagem pode ser feita de duas maneiras: com bloqueio ou sem bloqueio. O modo de bloqueio é ativado chamando o método setBackpressureStrategy() com STRATEGY_BLOCK_PRODUCER. Nesse modo, o executor recebe frames da câmera em ordem sequencial. Isso significa que, se o método analyze() levar mais tempo do que a latência de um único frame na taxa atual, os frames poderão não estar mais atualizados porque os novos serão impedidos de entrar no pipeline até o retorno do método.

O modo sem bloqueio é ativado ao chamar setBackpressureStrategy() com STRATEGY_KEEP_ONLY_LATEST. Neste modo, o executor recebe o último frame disponível da câmera no momento em que o método analyze() é chamado. Se o método demorar mais do que a latência de um único frame na taxa atual, alguns frames poderão ser ignorados para que, na próxima vez em que analyze() receber dados, ele tenha o último frame disponível no pipeline da câmera.

Antes de retornar de analyze(), feche a referência da imagem chamando image.close() para evitar o bloqueio da produção de outras imagens (fazendo com que a visualização pare) e evitar imagens que podem ser descartadas. O método precisa concluir a análise ou fazer uma cópia em vez de transmitir a referência da imagem além do método de análise.

Kotlin

val imageAnalysis = ImageAnalysis.Builder()
    .setTargetResolution(Size(1280, 720))
    .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
    .setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_RGBA_8888)
    .build()

imageAnalysis.setAnalyzer(executor, ImageAnalysis.Analyzer { image ->
    val rotationDegrees = image.imageInfo.rotationDegrees
    // insert your code here.
})

cameraProvider.bindToLifecycle(this as LifecycleOwner, cameraSelector, imageAnalysis, preview)

Java

ImageAnalysis imageAnalysis =
    new ImageAnalysis.Builder()
        .setTargetResolution(new Size(1280, 720))
        .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
        .setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_RGBA_8888)
        .build();

imageAnalysis.setAnalyzer(executor, new ImageAnalysis.Analyzer() {
    @Override
    public void analyze(@NonNull ImageProxy image) {
        int rotationDegrees = image.getImageInfo().getRotationDegrees();
            // insert your code here.
        }
    });

cameraProvider.bindToLifecycle((LifecycleOwner) this, cameraSelector, imageAnalysis, preview);

Por padrão, o CameraX define imagens no formato OUTPUT_IMAGE_FORMAT_YUV_420_888.

O aplicativo pode verificar o espaço de cores do ImageProxy transmitido pelo CameraX usando a função ImageProxy::getFormat(). Se ela retornar ImageFormat.YUV_420_888, a imagem estará no espaço de cores YUV. Se ela retornar PixelFormat.RGBA_8888, a imagem estará no espaço de cores RGBA.

O formato de saída YUV está disponível em todas as versões do camera-core. O formato de saída RGBA está disponível no camera-core:1.1.0-alpha09 e versões posteriores, apenas para o caso de uso da análise de imagens.

Ao configurar um formato de saída RGBA, o CameraX converte internamente imagens YUV para o espaço RGBA e armazena bits de imagem no ByteBuffer do primeiro plano do ImageProxy (outros planos não são usados) nesta sequência:

ImageProxy::planes[0].buffer[0]: alpha
ImageProxy::planes[1].buffer[1]: red
ImageProxy::planes[2].buffer[2]: green
ImageProxy::planes[3].buffer[3]: blue
...

A conversão de cores é uma etapa complementar ao formato de saída YUV, e o tempo de conversão faz parte do tempo total de análise da imagem. O aplicativo terá menos tempo de processamento por frame ao realizar análises em tempo real. Use a conversão quando o aplicativo precisar que a saída esteja no formato RGBA.

Outros recursos

Para saber mais sobre o CameraX, consulte os seguintes recursos.

Codelab

  • Introdução à CameraX
  • Exemplo de código

  • App de exemplo oficial do CameraX (link em inglês)