Construindo uma App para Reconhecimento de Objetos em Tempo Real com Tensorflow e OpenCV

Simony Cantanhede
Machina Sapiens
Published in
5 min readNov 4, 2017

Artigo traduzido do original “Building a Real-Time Object Recognition App with Tensorflow and OpenCV” de autoria do Dat Tran.

Tradução: Simony Cantanhede

Nesta matéria demonstrarei, de forma simples, o passo-a-passo para a construção de uma aplicação capaz de reconhecer objetos em tempo real utilizando a nova API de detecção de objetos da Tensorflow e o OpenCV em Python 3 (mais especificamente, com a versão 3.5 do Python).

Me concentrarei na descrição dos desafios que tive de superar quando estava tentando construir a minha própria aplicação, para que você, leitor, fique esperto quando estiver colocando a mão na massa.

Você pode encontrar o código completo aqui no meu repositório.

E aqui está uma demonstração da app em execução:

Motivação

Há pouco tempo a Google lançou sua nova API de detecção de objetos TensorFlow. Esta primeira versão contém:

  • Alguns modelos pré-treinados (é preciso ressaltar que houve um cuidado especial em fornecer modelos leves, que podem rodar sem problemas em dispositivos móveis);
  • Um exemplo de como montar um “Jupyter Notebook”[1] de um destes modelos disponíveis;
  • E alguns scripts bem práticos que podem ser utilizados para re-treinar os modelos disponíveis usando um dataset de sua própria autoria, caso você deseje fazê-lo.

Tendo em vista todas essas possibilidades, eu não via a hora de colocar minhas mãos em todo esse material incrível e dedicar alguma parte de meu tempo para construir algum tipo de aplicação capaz de reconhecer objetos em tempo real.

Aplicação

Primeiro, eu baixei o repositório de modelos do TensorFlow e então dei uma boa olhada no “jupyter notebook” que o acompanha: basicamente, ele descreve todas as etapas para o uso de um modelo pré-treinado. Neste exemplo, em específico, eles usaram o modelo “SSD com Mobilenet”, mas há muitos outros modelos disponíveis para download em um repositório que eles chamaram de “Tensorflow detection model zoo”. Os modelos deste repositório são treinados com o dataset COCO e variam dependendo da velocidade do modelo (lento, médio e rápido) e de sua performance (mAP — baseada na precisão média).

Em seguida, eu executei o exemplo. Vale ressaltar o quão bem documentado é o exemplo disponibilizado, tanto que, é bem fácil entender logo de cara suas principais funções:

1. Importar os pacotes necessários como o TensorFlow, PIL, etc. ;

2. Definir algumas variáveis, por exemplo: número de classe, nome do modelo, etc. ;

3. Baixar o modelo pré-computado (extensão .pb — “protobuf” [2]) e carregá-lo na memória ;

4. Carregar códigos auxiliares, por exemplo um índice para rotular o tradutor ;

5. O próprio código de detecção já contendo duas imagens para teste.

OBS: Antes de executar o exemplo, dê uma olhada nas observações de configuração, especialmente, naquelas que se referem à compilação do “protobuf”. Se você não rodar este comando aqui embaixo, o exemplo não vai funcionar:

# From tensorflow/models/research/
protoc object_detection/protos/*.proto --python_out=.

Depois de ter executado o exemplo e começar a ter alguma de noção de como ele funcionava, eu modifiquei o código original da seguinte maneira:

  • Excluí a seção de download do modelo;
  • Excluí também a dependência da biblioteca PIL, pois os fluxos de vídeo no OpenCV já estão no formato de arrays numpy. Além disso, PIL também é uma sobrecarga muito grande, especificamente ao usá-lo para leitura de imagens nos streams de vídeo;
  • Nenhuma declaração “com” para a sessão TensorFlow, pois esta é uma sobrecarga enorme, principalmente quando é necessário reiniciar a sessão depois de cada stream.

Daí eu utilizei o OpenCV para fazer a conexão entre o exemplo modificado e minha webcam. Há vários tutoriais disponíveis em vários cantos da internet que explicam direitinho como fazer essa conexão, além da documentação oficial no próprio site do OpenCV.

Geralmente, a implementação básica de exemplos OpenCV não é otimizada, por exemplo, algumas funções em OpenCV estão fortemente vinculadas à entrada e saída de dados. Por causa disso, eu tive que buscar algumas soluções para contornar este problema:

  • A leitura de frames através da webcam provoca um intenso fluxo de entrada e saída de dados. Minha ideia foi transferir essa responsabilidade para um novo processo Python que utilizasse uma biblioteca de multiprocessamento. Mas, infelizmente, isto não funcionou. Havia algumas explicações no Stackoverflow sobre o porque uma solução como esta não funcionaria, mas não consegui me aprofundar muito no assunto. Felizmente, encontrei um exemplo muito bom do Adrian Rosebrock em seu site “pyimagesearch” usando threading em vez de multiprocessamento, o que melhorou bastante o meu fps. Por sinal, se você quiser saber a diferença entre multiprocessamento e threading, no Stackoverflow você vai encontrar ótimas explicações.
  • O carregamento do modelo pré-computado na memória a cada vez que a aplicação inicializa provoca uma enorme sobrecarga. Primeiro eu tentei solucionar utilizando uma sessão TensorFlow para cada execução, mas o carregamento continuou muito lento. Então o que eu fiz para solucionar de vez o problema? A solução é bastante simples. Neste caso, usei a biblioteca de multiprocessamento para dividir a pesada carga de trabalho da detecção de objetos em múltiplos processos. O gatilho inicial da aplicação continuará lento, pois cada um desses processos precisa carregar o modelo na memória e iniciar a sessão do TensorFlow, mas, depois disso, o paralelismo nos ajudará.
  • Reduzir a largura e a altura dos frames no stream de vídeo também ajudou a melhorar bastante o fps.

OBS: Se você estiver em um Mac OSX como eu e estiver usando o OpenCV 3.1, pode haver uma chance de o VideoCapture da OpenCV falhar depois de um tempo. Voltar ao OpenCV 3.0 resolverá o problema.

Conclusão e considerações futuras

Me dê um 👏 se você gostou desta matéria :) Faça o download do código e experimente você mesmo. E definitivamente dê uma olhada na API Tensorflow Object Detection. É muito prático e simples desde o primeiro contato. A próxima coisa que eu quero tentar é treinar meu próprio conjunto de dados com a API e também usar os modelos pré-treinados para outras aplicações que tenho em mente. Eu também não estou totalmente satisfeito com o desempenho desta aplicação ainda. A taxa de fps ainda não está otimizada. Há muitos gargalos no OpenCV que ainda não consegui contornar, mas há alternativas que eu posso experimentar, tais como usar o WebRTC. Entretanto, esta alteração precisaria ser baseada em web. Além disso, estou pensando em usar chamadas de método assíncronas (async) para melhorar minha taxa de fps. Fique ligado nas possíveis atualizações!

[1] “Jupyter Notebook” é uma aplicação web open-source integrante do Projeto Jupyter cujo objetivo é permitir a criação e o compartilhamento de documentos que contenham a um só tempo código-fonte, equações, visualizações e textos narrativos. Um “jupyter notebook” suporta mais de 40 linguagens de programação; pode ser compartilhado por meio de e-mail, dropbox e GitHub; pode gerar saídas interativas em diversos formatos, desde HTML até imagens e vídeos; e também suporta ferramentas de big data como o Apache Spark, R e Scala, além do TensorFlow. Para saber mais sobre o projeto clique aqui.

[2] Um “protobuffer” (ou “protocol buffer”) é um mecanismo extensível criado pela Google capaz de executar em várias plataformas e em várias linguagens com o objetivo de serializar dados estruturados — algo como o XML, porém mais rápido, leve e simples. Saiba mais em: https://developers.google.com/protocol-buffers/ .

--

--