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 pela câmera de um 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 avançar 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 para identificar a presença e localização de múltiplas 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 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 ser 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 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 maior de detecção de objetos EfficientDet. O mAP para o conjunto de dados de validação COCO 2017 é de 33,97%.

  • MobileNetV1-SSD – um modelo extremamente leve otimizado para funcionar com o 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 construçã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 versão mínima do sistema operacional SDK 24 (Android 7.0 - Nougat) com 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 exemplo.

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 git para usar checkout esparso, para que você tenha apenas os arquivos do aplicativo de exemplo de detecção de objetos:
    cd examples
    git sparse-checkout init --cone
    git sparse-checkout set lite/examples/object_detection/android
    

Importe e execute o projeto

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

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

  1. Inicie o Android Studio .
  2. No Android Studio, selecione Arquivo > Novo > Importar Projeto .
  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 uma sincronização do Gradle, escolha OK.
  5. Certifique-se de que seu dispositivo Android esteja conectado ao computador e que o modo de desenvolvedor esteja ativado. Clique na seta verde Run .

Se você selecionar o diretório correto, o Android Studio criará um novo projeto e o compilará. Este processo pode demorar alguns minutos, dependendo da velocidade do seu computador e se você utilizou 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 Android da seguinte forma:

    // 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: Arquivo > Sincronizar projeto com arquivos Gradle .

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 machine learning do TensorFlow Lite e acessar funções utilitárias que convertem dados como imagens em um formato de dados 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 de projeto e módulo necessárias 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 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 machine learning 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 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 no 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 do modelo, como limite de previsão, tamanho do conjunto de resultados e, opcionalmente, delegados de aceleração de hardware:

    val optionsBuilder =
      ObjectDetector.ObjectDetectorOptions.builder()
        .setScoreThreshold(threshold)
        .setMaxResults(maxResults)
    
  4. Use as configurações deste objeto para construir um objeto ObjectDetector do TensorFlow Lite que contém 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 no seu aplicativo, você pode usar 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 de tensores (TPUs) e processadores de sinais digitais (DSPs). O uso de delegados para executar modelos do TensorFlow Lite é recomendado, mas não obrigatório.

O detector de objetos é inicializado usando as configurações atuais do thread que o utiliza. Você pode usar delegados de CPU e NNAPI com detectores criados no thread principal e usados ​​em um thread de segundo plano, mas o thread 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

No 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 Tensor que pode ser processado pelo 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 dos dados usados ​​para treinar o modelo.

O modelo EfficientDet-Lite0 usado neste exemplo de código aceita Tensores representando imagens com 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 os dados da imagem em objetos de dados do Tensor desse tamanho e formato. A API Vision da biblioteca de tarefas do TensorFlow Lite cuida da 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 atender aos requisitos de dados de imagem do modelo. A imagem é então traduzida em um objeto TensorImage .

Para preparar dados do subsistema de 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 ao 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 finais de dados 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 automaticamente dados ao modelo para previsões quando o aplicativo está conectado à câmera.

O aplicativo usa o método cameraProvider.bindToLifecycle() para lidar com 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

No 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 seu aplicativo deve manipular executando lógica de negócios adicional, exibindo resultados ao usuário ou executando outras ações.

A saída de qualquer modelo do TensorFlow Lite varia em termos do número de previsões que ele produz (uma ou muitas) e das 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 atua 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 predição inclui uma localização de caixa delimitadora para o objeto, um rótulo para o objeto e uma pontuação de predição entre 0 e 1 como um Float representando a confiança da predição, sendo 1 a classificação de confiança mais alta . Em geral, as previsões com pontuação inferior a 50% (0,5) são consideradas inconclusivas. No entanto, a maneira 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 listener para transmitir resultados ao código do aplicativo ou aos objetos da interface do usuário. O aplicativo de exemplo usa esse padrão para transmitir resultados de detecção do objeto ObjectDetectorHelper para o objeto CameraFragment :

    objectDetectorListener.onResults(
    // instance of CameraFragment
        results,
        inferenceTime,
        tensorImage.height,
        tensorImage.width)
    
  2. Aja de acordo com os resultados, como exibir a previsão ao 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 de acordo com essa previsão apresentando o resultado ao usuário ou executando lógica adicional. No caso do código de exemplo, a aplicação 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 .