Anotação automática de imagens usando o TensorFlow object detection

Alvaro Leandro Cavalcante Carneiro
Ensina.AI
Published in
6 min readJan 3, 2020
https://hackernoon.com/hn-images/1*_ptBWjaV6FgVPgOYd5UZVg.png

Este artigo e a biblioteca explicada estão desatualizados, por favor, olhe meu novo artigo para conferir a nova versão dessa ferramenta: https://medium.com/p/acf410a600b8

Todo mundo que já trabalhou com detecção de objetos em algum projeto sabe o quão chato e quanto tempo é gasto para fazer a anotação de imagens.

O processo de criar Labels em si é bastante fácil, como podemos ver no GIF abaixo, apenas precisamos marcar a localização do objeto de interesse e dizer sua classe. Não há problemas em seguir essa abordagem para apenas algumas imagens, porém quando temos centenas ou até milhares de observações no nosso dataset, o que é normal quando falamos de deep learning, isso se torna um desafio muito grande e um possível gargalo no projeto.

Experimente fazer isso para mil imagens…

No meu projeto eu tive criar um dataset de folhas de café com pragas e doenças e claro, anotar as imagens manualmente. Testei alguns softwares para fazer esse trabalho, inclusive alguns que prometiam facilitar ou automatizar o processo (pode até funcionar se o seu objeto de interesse for simples) mas o que mais me agradou foi o LabelImage (https://github.com/tzutalin/labelImg).

Mas claro que essa abordagem não me deixava satisfeito, eu estava gastando todo o meu tempo para criar e anotar os dados e quase nada para testar e aprender mais sobre os diversos modelos sofisticados de detecção de objetos.

Foi ai que surgiu a ideia de criar um jeito simples para me auxiliar, de forma assistida, a criação de novas Labels e deixar a tarefa mais prática e escalável.

Como a abordagem funciona?

Essa abordagem utiliza muita das classes já existentes no próprio repositório do TensorFlow, porém, eu criei uma nova classe chamada GenerateXml() o qual é responsável por transformar as inferências de um modelo pré treinado em uma arquivo XML contendo a posição das caixas delimitadoras.

Como você deve ter reparado, é necessário ter um modelo pré treinado, portanto no fim das contas você não vai conseguir fugir completamente do trabalho manual, todavia isso só será necessário para algumas imagens, dependendo claro da complexidade do seu problema.

No meu caso, anotei aproximadamente 120 imagens manualmente e a partir daí, as outras centenas foram feitas com a ajuda dessa classe.

Colocando a mão na massa

Dentro da pasta research/object_detection no repositório do TF está quase tudo que você vai precisar. Caso tenha alguma dúvida sobre o funcionamento do TF object detection, você poderá dar uma olhada no notebook chamado object_detection_tutorial dentro dessa pasta, onde eles explicam os detalhes de carregar o modelo e criar novas inferências.

No meu projeto, eu usei uma REST API de NodeJS, mas para fins didáticos vamos criar um esquema de diretórios simplificado para entender o comportamento da classe.

Primeiro vamos criar uma pasta para nosso projeto, eu chamei ela de auto_annotate, e dentro dessa pasta ‘principal’ temos as seguintes subpastas: images, scripts, results, graphs e xml.

  • Images contém todas as imagens que iremos inferir para criar as Labels
  • Results é o resultado da inferência do modelo
  • Script contém os scripts python que vamos usar
  • Graphs contém o frozen inference graph e o label map.

Você pode encontrar o meu código e também essa estrutura que foi descrita no meu GitHub: https://github.com/AlvaroCavalcante/auto_annotate

O arquivo principal é o detection_images.py, responsável por carregar o modelo e criar as novas inferências a partir dele das imagens na pasta.

Você vai precisar modificar as primeiras linhas desse arquivo para adicionar o seu próprio caminho se a sua estrutura for diferente da minha.

Eu também adicionei algumas linhas para mudar a dimensão da imagem e o salvamento dos resultados, porém todo o resto é similar ao arquivo original que você pode encontrar na pasta TensorFlow.

A nossa classe GenerateXml() no arquivo generate_xml.py recebe do modelo o nome da classe inferida, as dimensões da imagem e um array de dicionários com as coordenadas das caixas delimitadoras.

Essas informações são passadas pelo arquivo visualization_utils.py, também encontrado na pasta do TensorFlow, apenas precisei fazer algumas adaptações:

array_position = []im_height, im_width, shape = image.shape #get image dimensionsfor box, color in box_to_color_map.items(): #loop in predicted boxesymin, xmin, ymax, xmax = boxdict_position = {'xmin': 0, 'xmax': 0, 'ymin': 0, 'ymax': 0}dict_position['ymin'] = ymin * im_height #add the positions to the #dict, we multiply to get the real value in pixelsdict_position['xmin'] = xmin * im_widthdict_position['ymax'] = ymax * im_heightdict_position['xmax'] = xmax * im_widtharray_position.append(dict_position)

Após feito esses ajustes, nós precisamos apenas instanciar a classes e rodar o método generate_basic_structure() para criar nossas labels.

if new_xml != False: #this statement prevents to call the class with # we don't have predictions in the image.xml = generate_xml.GenerateXml(array_position, im_width, im_height, class_name)xml.gerenate_basic_structure()

Neste método, nós usamos o ElementTree (o qual você irá precisar instalar via pip) para criar a estrutura do XML. Note que a estrutura que nós criamos é a mesma gerada pelo LabelImage.

É importante lembrar que o arquivo xml deve ter o mesmo nome da imagem que foi inferida, por exemplo a imagem1.jpg vai gerar o arquivo imagem1.xml.

Para isso usamos o método “get_file_name” que retorna uma numeração e adiciona ao fim do nome do arquivo XML, todavia para que tudo funcione corretamente você também precisará mudar o nome das suas imagens para respeitar esse padrão.

Antes de rodar o algoritmo você vai precisar substituir o arquivo visualization_utils.py na pasta research/object_detection/utils do TensorFlow pelo arquivo que modificamos. (Lembre que sempre há novas mudanças no repositório do TensorFlow, portanto, dependendo de quando você estiver vendo esse tutorial, apenas substituir o arquivo não funciona, sendo mais seguro copiar e colar as linhas que foram modificadas na posição em que elas se encontram no nosso arquivo).

Você também vai precisar copiar e colar o arquivo generate_xml.py para a mesma pasta utils do nosso arquivo visualization_utils.py.

Depois disso, basta entrar na sus paste (auto_annotate no meu caso) e executar o comando:

python3 scripts/detection_images.py

Se tudo estiver funcionando você vai ver dentro da pasta de results os resultados das images que foram inferidas:

Minhas folhas de café inferidas pelo modelo

E na pasta de xml você irá encontrar os arquivos contendo as anotações. Vamos abrir as imagens e o arquivo xml no LabelImage.

Ai estamos!!! Labels criadas automaticamente

Claro que ainda não está perfeito, você pode querer fazer alguns ajustes nas posições das caixas delimitadoras para ficar mais preciso e claro, criar as labels manualmente caso o seu modelo pré treinado não faça a inferência corretamente, mas podemos dizer que esse método é mais rápido e prático do que fazer todo o trabalho de forma manual.

No meu caso eu usei esse algoritmo para criar as labels em aproximadamente 450 imagens em questão de poucos minutos.

Por fim, quanto mais treinamos nosso modelo as inferências também ficam mais precisas e menos precisamos gastar tempo com trabalho manual.

CONCLUSÃO

Uma forma mais automática de anotar o dataset é algo muito importante de se ter para quem trabalha com detecção de objetos, nos permitindo focar no que realmente importa ao invés de gastar tempo com a preparação dos dados.

Claro que isso é apenas o primeiro passo, eu espero que logo surjam novos métodos e algoritmos para facilitar ainda mais o processo.

Obrigado por ler, eu espero que esse tutorial tenha ajudado, se tiver alguma dúvida ou sugestão estou à disposição para ajudar.

Originally published at https://medium.com on January 3, 2020.

--

--

Alvaro Leandro Cavalcante Carneiro
Ensina.AI

MSc. Computer Science | Data Engineer. I write about artificial intelligence, deep learning and programming.