Detecção de objetos com Android

Este tutorial mostra como criar um aplicativo Android usando o TensorFlow Lite para detectar continuamente objetos em quadros capturados por uma câmera de dispositivo. Este aplicativo foi projetado para um dispositivo Android físico. Se você estiver atualizando um projeto existente, poderá usar o exemplo de código como referência e pular para as instruções para modificar seu projeto .

Demonstração animada de detecção de objetos

Visão geral da detecção de objetos

A detecção de objetos é a tarefa de aprendizado de máquina de identificar a presença e a localização de várias classes de objetos em uma imagem. Um modelo de detecção de objetos é treinado em um conjunto de dados que contém um conjunto de objetos conhecidos.

O modelo treinado recebe quadros de imagem como entrada e tenta categorizar itens nas imagens do conjunto de classes conhecidas que ele foi treinado para reconhecer. Para cada quadro de imagem, o modelo de detecção de objetos gera uma lista dos objetos que detecta, a localização de uma caixa delimitadora para cada objeto e uma pontuação que indica a confiança do objeto sendo classificado corretamente.

Modelos e conjunto de dados

Este tutorial usa modelos que foram treinados usando o conjunto de dados COCO . COCO é um conjunto de dados de detecção de objetos em grande escala que contém 330 mil imagens, 1,5 milhão de instâncias de objetos e 80 categorias de objetos.

Você tem a opção de usar um dos seguintes modelos pré-treinados:

  • EfficientDet-Lite0 [Recomendado] - um modelo leve de detecção de objetos com um extrator de recursos BiFPN, preditor de caixa compartilhada e perda focal. O mAP (precisão média média) para o conjunto de dados de validação COCO 2017 é de 25,69%.

  • EfficientDet-Lite1 - um modelo de detecção de objetos EfficientDet de tamanho médio. O mAP para o conjunto de dados de validação COCO 2017 é de 30,55%.

  • EfficientDet-Lite2 - um modelo de detecção de objeto EfficientDet maior. O mAP para o conjunto de dados de validação COCO 2017 é de 33,97%.

  • MobileNetV1-SSD - um modelo extremamente leve otimizado para trabalhar com TensorFlow Lite para detecção de objetos. O mAP para o conjunto de dados de validação COCO 2017 é de 21%.

Para este tutorial, o modelo EfficientDet-Lite0 atinge um bom equilíbrio entre tamanho e precisão.

O download, a extração e a colocação dos modelos na pasta de ativos são gerenciados automaticamente pelo arquivo download.gradle , que é executado no momento da compilação. Você não precisa baixar manualmente os modelos TFLite para o projeto.

Exemplo de configuração e execução

Para configurar o aplicativo de detecção de objetos, baixe o exemplo do GitHub e execute-o usando o Android Studio . As seções a seguir deste tutorial exploram as seções relevantes do exemplo de código, para que você possa aplicá-las aos seus próprios aplicativos Android.

requisitos de sistema

  • Android Studio versão 2021.1.1 (Bumblebee) ou superior.
  • Android SDK versão 31 ou superior
  • Dispositivo Android com uma versão mínima do SO do SDK 24 (Android 7.0 - Nougat) com o modo de desenvolvedor ativado.

Obtenha o código de exemplo

Crie uma cópia local do código de exemplo. Você usará esse código para criar um projeto no Android Studio e executar o aplicativo de amostra.

Para clonar e configurar o código de exemplo:

  1. Clone o repositório git
    git clone https://github.com/tensorflow/examples.git
    
  2. Opcionalmente, configure sua instância do git para usar check-out esparso, para que você tenha apenas os arquivos para o aplicativo de exemplo de detecção de objeto:
    cd examples
    git sparse-checkout init --cone
    git sparse-checkout set lite/examples/object_detection/android
    

Importar e executar o projeto

Crie um projeto a partir do código de exemplo baixado, compile o projeto e execute-o.

Para importar e construir o projeto de código de exemplo:

  1. Inicie o Android Studio .
  2. No Android Studio, selecione File > New > Import Project .
  3. Navegue até o diretório de código de exemplo que contém o arquivo build.gradle ( .../examples/lite/examples/object_detection/android/build.gradle ) e selecione esse diretório.
  4. Se o Android Studio solicitar um Gradle Sync, escolha OK.
  5. Certifique-se de que seu dispositivo Android esteja conectado ao seu computador e que o modo de desenvolvedor esteja ativado. Clique na seta verde Run .

Se você selecionar o diretório correto, o Android Studio cria um novo projeto e o compila. Esse processo pode levar alguns minutos, dependendo da velocidade do seu computador e se você já usou o Android Studio para outros projetos. Quando a compilação for concluída, o Android Studio exibirá uma mensagem BUILD SUCCESSFUL no painel de status Build Output .

Opcional: para corrigir erros de compilação atualizando a versão do plug-in do Android:

  1. Abra o arquivo build.gradle no diretório do projeto.
  2. Altere a versão das ferramentas do Android da seguinte maneira:

    // from: classpath
    'com.android.tools.build:gradle:4.2.2'
    // to: classpath
    'com.android.tools.build:gradle:4.1.2'
    
  3. Sincronize o projeto selecionando: File > Sync Project with Gradle Files .

Para executar o projeto:

  1. No Android Studio, execute o projeto selecionando Run > Run… .
  2. Selecione um dispositivo Android conectado com uma câmera para testar o aplicativo.

As próximas seções mostram as modificações que você precisa fazer em seu projeto existente para adicionar essa funcionalidade ao seu próprio aplicativo, usando este aplicativo de exemplo como ponto de referência.

Adicionar dependências do projeto

Em seu próprio aplicativo, você deve adicionar dependências de projeto específicas para executar modelos de aprendizado de máquina do TensorFlow Lite e acessar funções de utilitário que convertem dados, como imagens, em um formato de dados de tensor que pode ser processado pelo modelo que você está usando.

O aplicativo de exemplo usa a biblioteca de tarefas do TensorFlow Lite para visão para permitir a execução do modelo de aprendizado de máquina de detecção de objetos. As instruções a seguir explicam como adicionar as dependências de biblioteca necessárias ao seu próprio projeto de aplicativo Android.

As instruções a seguir explicam como adicionar as dependências necessárias do projeto e do módulo ao seu próprio projeto de aplicativo Android.

Para adicionar dependências de módulo:

  1. No módulo que usa o TensorFlow Lite, atualize o arquivo build.gradle do módulo para incluir as dependências a seguir. No código de exemplo, este arquivo está localizado aqui: ...examples/lite/examples/object_detection/android/app/build.gradle ( referência de código )

    dependencies {
      ...
      implementation 'org.tensorflow:tensorflow-lite-task-vision:0.4.0'
      // Import the GPU delegate plugin Library for GPU inference
      implementation 'org.tensorflow:tensorflow-lite-gpu-delegate-plugin:0.4.0'
      implementation 'org.tensorflow:tensorflow-lite-gpu:2.9.0'
    }
    

    O projeto deve incluir a biblioteca de tarefas Vision ( tensorflow-lite-task-vision ). A biblioteca da unidade de processamento gráfico (GPU) ( tensorflow-lite-gpu-delegate-plugin ) fornece a infraestrutura para executar o aplicativo na GPU e o Delegate ( tensorflow-lite-gpu ) fornece a lista de compatibilidade.

  2. No Android Studio, sincronize as dependências do projeto selecionando: File > Sync Project with Gradle Files .

Inicialize o modelo de ML

No seu aplicativo Android, você deve inicializar o modelo de aprendizado de máquina do TensorFlow Lite com parâmetros antes de executar previsões com o modelo. Esses parâmetros de inicialização são consistentes em todos os modelos de detecção de objetos e podem incluir configurações como limites mínimos de precisão para previsões.

Um modelo do TensorFlow Lite inclui um arquivo .tflite contendo o código do modelo e frequentemente inclui um arquivo de rótulos contendo os nomes das classes previstas pelo modelo. No caso de detecção de objetos, as classes são objetos como uma pessoa, cachorro, gato ou carro.

Este exemplo faz download de vários modelos especificados em download_models.gradle e a classe ObjectDetectorHelper fornece um seletor para os modelos:

val modelName =
  when (currentModel) {
    MODEL_MOBILENETV1 -> "mobilenetv1.tflite"
    MODEL_EFFICIENTDETV0 -> "efficientdet-lite0.tflite"
    MODEL_EFFICIENTDETV1 -> "efficientdet-lite1.tflite"
    MODEL_EFFICIENTDETV2 -> "efficientdet-lite2.tflite"
    else -> "mobilenetv1.tflite"
  }

Para inicializar o modelo em seu aplicativo:

  1. Adicione um arquivo de modelo .tflite ao diretório src/main/assets do seu projeto de desenvolvimento, como: EfficientDet-Lite0 .
  2. Defina uma variável estática para o nome do arquivo do seu modelo. No aplicativo de exemplo, você define a variável modelName como MODEL_EFFICIENTDETV0 para usar o modelo de detecção EfficientDet-Lite0.
  3. Defina as opções para o modelo, como o limite de previsão, o tamanho do conjunto de resultados e, opcionalmente, os delegados de aceleração de hardware:

    val optionsBuilder =
      ObjectDetector.ObjectDetectorOptions.builder()
        .setScoreThreshold(threshold)
        .setMaxResults(maxResults)
    
  4. Use as configurações desse objeto para construir um objeto ObjectDetector do TensorFlow Lite que contenha o modelo:

    objectDetector =
      ObjectDetector.createFromFileAndOptions(
        context, modelName, optionsBuilder.build())
    

O setupObjectDetector configura os seguintes parâmetros de modelo:

  • Limite de detecção
  • Número máximo de resultados de detecção
  • Número de threads de processamento a serem usados ​​( BaseOptions.builder().setNumThreads(numThreads) )
  • Modelo real ( modelName )
  • Objeto ObjectDetector ( objectDetector )

Configurar acelerador de hardware

Ao inicializar um modelo do TensorFlow Lite em seu aplicativo, você pode usar os recursos de aceleração de hardware para acelerar os cálculos de previsão do modelo.

Os delegados do TensorFlow Lite são módulos de software que aceleram a execução de modelos de aprendizado de máquina usando hardware de processamento especializado em um dispositivo móvel, como unidades de processamento gráfico (GPUs), unidades de processamento tensor (TPUs) e processadores de sinal digital (DSPs). O uso de representantes para executar modelos do TensorFlow Lite é recomendado, mas não obrigatório.

O detector de objetos é inicializado usando as configurações atuais no thread que o está usando. Você pode usar delegados de CPU e NNAPI com detectores criados no encadeamento principal e usados ​​em um encadeamento em segundo plano, mas o encadeamento que inicializou o detector deve usar o delegado de GPU.

Os delegados são definidos na função ObjectDetectionHelper.setupObjectDetector() :

when (currentDelegate) {
    DELEGATE_CPU -> {
        // Default
    }
    DELEGATE_GPU -> {
        if (CompatibilityList().isDelegateSupportedOnThisDevice) {
            baseOptionsBuilder.useGpu()
        } else {
            objectDetectorListener?.onError("GPU is not supported on this device")
        }
    }
    DELEGATE_NNAPI -> {
        baseOptionsBuilder.useNnapi()
    }
}

Para obter mais informações sobre como usar delegados de aceleração de hardware com o TensorFlow Lite, consulte Delegados do TensorFlow Lite .

Preparar dados para o modelo

Em seu aplicativo Android, seu código fornece dados ao modelo para interpretação, transformando dados existentes, como quadros de imagem, em um formato de dados do Tensor que pode ser processado por seu modelo. Os dados em um tensor que você passa para um modelo devem ter dimensões ou formas específicas que correspondam ao formato de dados usado para treinar o modelo.

O modelo EfficientDet-Lite0 usado neste exemplo de código aceita Tensores que representam imagens com uma dimensão de 320 x 320, com três canais (vermelho, azul e verde) por pixel. Cada valor no tensor é um único byte entre 0 e 255. Portanto, para executar previsões em novas imagens, seu aplicativo deve transformar esses dados de imagem em objetos de dados do Tensor desse tamanho e formato. A API de visão da biblioteca de tarefas do TensorFlow Lite lida com a transformação de dados para você.

O aplicativo usa um objeto ImageAnalysis para extrair imagens da câmera. Este objeto chama a função detectObject com bitmap da câmera. Os dados são redimensionados e girados automaticamente pelo ImageProcessor para que atendam aos requisitos de dados de imagem do modelo. A imagem é então traduzida em um objeto TensorImage .

Para preparar os dados do subsistema da câmera para serem processados ​​pelo modelo de ML:

  1. Crie um objeto ImageAnalysis para extrair imagens no formato necessário:

    imageAnalyzer =
        ImageAnalysis.Builder()
            .setTargetAspectRatio(AspectRatio.RATIO_4_3)
            .setTargetRotation(fragmentCameraBinding.viewFinder.display.rotation)
            .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
            .setOutputImageFormat(OUTPUT_IMAGE_FORMAT_RGBA_8888)
            .build()
            ...
    
  2. Conecte o analisador ao subsistema da câmera e crie um buffer de bitmap para conter os dados recebidos da câmera:

    .also {
      it.setAnalyzer(cameraExecutor) {
        image -> if (!::bitmapBuffer.isInitialized)
        { bitmapBuffer = Bitmap.createBitmap( image.width, image.height,
        Bitmap.Config.ARGB_8888 ) } detectObjects(image)
        }
      }
    
  3. Extraia os dados de imagem específicos necessários para o modelo e passe as informações de rotação da imagem:

    private fun detectObjects(image: ImageProxy) {
      //Copy out RGB bits to the shared bitmap buffer
      image.use {bitmapBuffer.copyPixelsFromBuffer(image.planes[0].buffer) }
        val imageRotation = image.imageInfo.rotationDegrees
        objectDetectorHelper.detect(bitmapBuffer, imageRotation)
      }
    
  4. Conclua todas as transformações de dados finais e adicione os dados da imagem a um objeto TensorImage , conforme mostrado no método ObjectDetectorHelper.detect() do aplicativo de exemplo:

    val imageProcessor = ImageProcessor.Builder().add(Rot90Op(-imageRotation / 90)).build()
    // Preprocess the image and convert it into a TensorImage for detection.
    val tensorImage = imageProcessor.process(TensorImage.fromBitmap(image))
    

Executar previsões

No seu aplicativo Android, depois de criar um objeto TensorImage com dados de imagem no formato correto, você pode executar o modelo nesses dados para produzir uma previsão ou inferência .

Na classe fragments/CameraFragment.kt do aplicativo de exemplo, o objeto imageAnalyzer dentro da função bindCameraUseCases passa dados automaticamente para o modelo para previsões quando o aplicativo é conectado à câmera.

O aplicativo usa o método cameraProvider.bindToLifecycle() para manipular o seletor de câmera, a janela de visualização e o processamento do modelo de ML. A classe ObjectDetectorHelper.kt trata da passagem dos dados da imagem para o modelo. Para executar o modelo e gerar previsões a partir de dados de imagem:

  • Execute a previsão passando os dados da imagem para sua função de previsão:

    val results = objectDetector?.detect(tensorImage)
    

O objeto TensorFlow Lite Interpreter recebe esses dados, executa-os no modelo e produz uma lista de previsões. Para processamento contínuo de dados pelo modelo, use o método runForMultipleInputsOutputs() para que os objetos Interpreter não sejam criados e removidos pelo sistema para cada execução de previsão.

Lidar com a saída do modelo

Em seu aplicativo Android, depois de executar dados de imagem no modelo de detecção de objetos, ele produz uma lista de previsões que o código do aplicativo deve processar executando lógica de negócios adicional, exibindo resultados para o usuário ou realizando outras ações.

A saída de qualquer modelo do TensorFlow Lite varia de acordo com o número de previsões que ele produz (uma ou muitas) e as informações descritivas de cada previsão. No caso de um modelo de detecção de objetos, as previsões normalmente incluem dados para uma caixa delimitadora que indica onde um objeto é detectado na imagem. No código de exemplo, os resultados são passados ​​para a função onResults em CameraFragment.kt , que está atuando como um DetectorListener no processo de detecção de objetos.

interface DetectorListener {
  fun onError(error: String)
  fun onResults(
    results: MutableList<Detection>?,
    inferenceTime: Long,
    imageHeight: Int,
    imageWidth: Int
  )
}

Para o modelo usado neste exemplo, cada previsão inclui um local de caixa delimitadora para o objeto, um rótulo para o objeto e uma pontuação de previsão entre 0 e 1 como um Float representando a confiança da previsão, sendo 1 a classificação de confiança mais alta . Em geral, as previsões com pontuação abaixo de 50% (0,5) são consideradas inconclusivas. No entanto, a forma como você lida com resultados de previsão de baixo valor depende de você e das necessidades do seu aplicativo.

Para lidar com os resultados da previsão do modelo:

  1. Use um padrão de ouvinte para passar resultados para o código do aplicativo ou objetos da interface do usuário. O aplicativo de exemplo usa esse padrão para passar resultados de detecção do objeto ObjectDetectorHelper para o objeto CameraFragment :

    objectDetectorListener.onResults(
    // instance of CameraFragment
        results,
        inferenceTime,
        tensorImage.height,
        tensorImage.width)
    
  2. Aja sobre os resultados, como exibir a previsão para o usuário. O exemplo desenha uma sobreposição no objeto CameraPreview para mostrar o resultado:

    override fun onResults(
      results: MutableList<Detection>?,
      inferenceTime: Long,
      imageHeight: Int,
      imageWidth: Int
    ) {
        activity?.runOnUiThread {
            fragmentCameraBinding.bottomSheetLayout.inferenceTimeVal.text =
                String.format("%d ms", inferenceTime)
    
            // Pass necessary information to OverlayView for drawing on the canvas
            fragmentCameraBinding.overlay.setResults(
                results ?: LinkedList<Detection>(),
                imageHeight,
                imageWidth
            )
    
            // Force a redraw
            fragmentCameraBinding.overlay.invalidate()
        }
    }
    

Depois que o modelo retornar um resultado de previsão, seu aplicativo poderá agir nessa previsão apresentando o resultado ao usuário ou executando lógica adicional. No caso do código de exemplo, o aplicativo desenha uma caixa delimitadora ao redor do objeto identificado e exibe o nome da classe na tela.

Próximos passos

  • Explore vários usos do TensorFlow Lite nos exemplos .
  • Saiba mais sobre como usar modelos de machine learning com o TensorFlow Lite na seção Modelos .
  • Saiba mais sobre como implementar o aprendizado de máquina em seu aplicativo móvel no Guia do desenvolvedor do TensorFlow Lite .