Busca por objetos em Imagens com Amazon Rekognition e ElasticSearch

Rodrigo Macedo
Ensina.AI
Published in
15 min readJun 21, 2018
Fonte: https://medium.com/@rcarneironet/vis%C3%A3o-computacional-com-javascript-detectando-rostos-956c77ea1273

Muito provável que você já tenha ouvido bastante sobre Visão Computacional. Muito pelo fato, de uma proporção cada vez maior de dados (cujo termo se cunhou de Big Data), e também pelo avanço da computação paralela em GPUs. No entanto, ainda existem alguns percalços para que esse tipo de conhecimento (que vem impactando e transformando negócios), se torne mais acessível para aqueles que tenham desejo de criar aplicações utilizando Visão Computacional. Em paralelo a esses e outros questionamentos, temos presenciado ultimamente, um grande avanço das plataformas de Cloud Computing (Computação em Nuvem), principalmente, quando as empresas que lideram esse mercado hoje, que são a Amazon, Microsoft e Google, decidiram começar a investir em Big Data, Machine Learning e Inteligência Artificial em suas respectivas plataformas. Nesse artigo, apresentaremos alguns serviços de uma dessas plataformas (Amazon AWS), para criarmos uma aplicação de busca por objetos detectados em imagens. Como, iremos mostrar passo, a passo, sobre a arquitetura da aplicação, decidimos não comentar sobre a abordagem teórica da Detecção de Objetos nesse artigo, por ser um assunto tão vasto, pode ser facilmente trabalhado num próximo artigo. Vou presumir também que você já tenha uma conta na Amazon AWS criada, ainda que seja uma conta free durante o período de 12 meses. Entrando na plataforma da Amazon AWS, procurando pelos serviços do grupo de Machine Learning, encontramos o Amazon Rekognition. Este serviço abstrai e facilita bastante a construção de aplicações de Visão Computacional. Algumas das funcionalidades cobertas por este serviço são:

  • Detecção de objetos e cenas, inclusive vai ser esta funcionalidade que estaremos adicionando em nossa aplicação, durante o artigo, entro mais em detalhes sobre esta funcionalidade.
  • Moderação de imagens, muito interessante para aplicações que precisam filtrar imagens para visualização, de acordo com publico alvo.
  • Análise facial, funcionalidade bem incrível. Você faz o upload de alguma imagem, o algoritmo vai inferir algumas informações a partir da foto, como: a pessoa é do sexo feminino ou masculino, faixa etária de idade, análise de emoções: está triste, feliz, dentre outras características. Vale a pena conferir.
  • Reconhecimento de celebridades, esta é uma função bem nova. A ideia é que você teste o reconhecimento no algoritmo de pessoas conhecidas, como, jogadores de futebol, atores, presidentes, etc.
  • Comparação de faces, funcionalidade bem incrível também, ela une detecção e reconhecimento facial na prática, para analisar a comparação entre diferentes faces. Há infinitas possibilidades de aplicações a serem criadas, que utilizam essa funcionalidade. Inclusive, fiz um post sobre essa funcionalidade, alguns dias atrás em um blog pessoal. Caso queiram ver, acesse esse link.
  • Texto em Imagem, outra funcionalidade bem incrível, esta permite detectar textos, logotipos, marcas em imagens. Vale a pena conferir também.

Perceba que há diversas possibilidades de construir infindas aplicações com essas funcionalidades que citamos acima. Nesse artigo, iremos abordar a primeira funcionalidade. Veja como é simples a utilização dessa funcionalidade, dentro do Amazon Rekognition:

Exemplo de Detecção de Objetos no Rekognition.

Veja na imagem acima, que o próprio Amazon Rekognition, trouxe uma imagem de exemplo, e o algoritmo fez a detecção de objetos e cenas, e encontrou com um alto grau de precisão, objetos como: Skate, Pessoas, etc. O bacana também, é que você pode fazer upload de outras imagens, dentro dessa plataforma. Apesar dessa facilidade, muitas empresas estão utilizando o Amazon Rekognition para incorporar novas funcionalidades em seus produtos: seja um site ou um aplicativo. É isso que veremos aqui no post. Para isso, precisamos, utilizar o SDK do Rekognition, cuja documentação, pode ser encontrada neste link. Antes de começarmos o desenvolvimento da aplicação, vou apresentar a arquitetura da aplicação:

Arquitetura da aplicação.

Essa será a arquitetura da nossa aplicação. Os principais serviços que utilizaremos, serão: o Rekognition, para fazer a detecção de objetos, e o ElasticSearch, que possibilitará com que façamos as pesquisas com um alto desempenho. Os demais serviços, como o Amazon S3, Lambda, API Gateway, foram utilizados como forma de suporte à aplicação, e são essenciais para o funcionamento da aplicação. Utilizaremos o Python para desenvolvimento da aplicação. A primeira coisa que precisamos é ir até o Amazon ElasticSearch Service, é criar um domínio, que será utilizado para armazenamento de documentos e busca em nossa aplicação. Caso você queira reproduzir essa aplicação, saiba que todos os recursos que utilizamos na aplicação, estão gratuitos até que seja atingido um determinado limite. Para mais informações sobre os serviços da camada gratuita, recomendo esse link. Para criar um domínio no ElasticSearch, basta preencher as informações a seguir:

Criação de domínio no ElasticSearch.

Após a criação do domínio, você vai ser redirecionado para as informações do painel do seu domínio no ElasticSearch:

Painel de Informações do domínio no ElasticSearch.

Note que temos três informações bastante importantes na imagem acima, que são: o Endpoint, é por ele que você vai comunicar com a sua aplicação, o Domain ARN, e o Kibana, que é um serviço para consultar os documentos e gerar visualizações de dados, falaremos sobre ele mais a frente. Essas três informações estão vazias, pois eu alterei o valor delas na inspeção de elementos, para me certificar de que estarei utilizando o serviço sob o limite da camada gratuita. Feito isso, podemos ir para o Python, e a primeira função que teremos, é a de conexão com o domínio criado com o ElasticSearch:

Este arquivo Python, tem por nome indexa.py. Nele faremos a conexão com o ElasticSearch, faremos a detecção de objetos com as imagens que fizermos o upload, e também adicionaremos as informações de detecção dos objetos dentro do ElasticSearch, para que depois possamos pesquisar os objetos nas imagens. Mas primeiro, vamos trabalhando com os métodos separados, e comentando sobre eles. No código acima, temos as importações necessárias para o arquivo, que vão da linha 1 até a linha 4. E temos um método para conectar ao ElasticSearch. Na linha 24, você precisa passar como parâmetro para este método, o nome do domínio que foi criado lá no ElasticSearch. Não é necessário colocar o protocolo https, pode começar pelo nome do domínio mesmo, exemplo: search-pesquisa-[Demais informações]. Feito isso, e executando a função, deve ser retornado o seguinte no terminal: Connecting to the ES Endpoint. Antes de darmos continuidade ao desenvolvimento, é necessário a criação de um bucket no S3. O S3 (Simple Storage Service) é um dos serviços mais populares do Amazon AWS, e será utilizado em nossa aplicação para podermos fazer o upload das imagens que quisermos detectar os objetos.

Criação do bucket S3.

O nome de um bucket no S3, é único em toda a plataforma da AWS, caso você tente um nome, e der erro, tenta colocar um nome um pouco mais específico. Criado o bucket, você precisa clicar dentro dele, ir na aba Permissions e na categoria Bucket-Policy.

Permissões no Bucket-Policy.

O código a ser adicionado nessa política do bucket, é o seguinte:

Apenas uma alteração, na linha 9, o que está entre colchetes, precisa ser colocado o nome do seu bucket criado. Feito isso, pode clicar em salvar. Mas ainda precisamos de mais uma configuração, que é sobre os CORS.

Configurações do CORS no Bucket.

O código da configuração, você encontra a seguir:

Note que habilitamos alguns métodos HTTP para esse nosso bucket. No nosso caso, utilizaremos apenas dois métodos, que é o GET, para listar todas as imagens em nossa aplicação, e o POST, para permitir o upload das imagens. Feito essas configurações, podemos dar continuidade ao desenvolvimento da aplicação, com as funções de detectar objetos nas imagens, e criar um documento do resultado da detecção no ElasticSearch.

Sem dúvidas, essa é a parte mais importante desse arquivo. Nas linhas 2 a 14, fazemos a detecção de objetos utilizando o Amazon Rekognition. Veja que, para isso, precisamos informar o nome do bucket, que foi esse que nós criamos, e uma key, que vai representar o nome da imagem que fizermos o upload. É por isso, que vamos fazer o deploy desta função no AWS Lambda, para conseguirmos capturar o nome da imagem a cada upload que fizermos. Note também, que passamos como configuração padrão nessa função, que queremos apenas cinco objetos detectados em cada imagem, e que o nível mínimo de precisão que queremos na detecção dos objetos é de 90%. Por fim, nas linhas 16 a 26, vamos interagir a nossa aplicação com o ElasticSearch. A cada detecção de objetos que nosso algoritmo fizer, vamos capturar o nome de cada imagem (linha 19), e vamos adicionar essa informação em um dicionário, que irá conter informações dos objetos detectados, e do endereço de cada imagem no bucket S3. Temos que fazer dessa forma, pois o ElasticSearch utilizando JSON (Javascript Object Notation), as informações são agrupadas em pares de chave e valor, no nosso caso, temos duas chaves, título e labels, sendo que uma receberá o endereço da imagem no bucket, e o outro, uma lista com os objetos contidos naquela imagem. E por último, informamos na linha 26, o índice do documento, e o corpo, que nada mais é do que os pares de chave e valor que definimos na linha 21. Pronto. Já temos 50% da aplicação construída. O que precisamos agora, antes de irmos para a implementação da busca, é informamos como o AWS Lambda vai executar essa aplicação. Mas antes, vou mostrar como capturarmos a lista de imagens que temos no nosso bucket atual, e salvar essa informações num arquivo JSON, para posteriormente, criar uma listagem de imagens na aplicação web.

As funções a seguir, são bem tranquilas. A primeira, da linha 1 a 7, vai iterar sobre um determinado bucket e retornar os dados que lá estiverem. Para isso, você precisa informar na linha 03, o nome do bucket que você criou para armazenar as imagens. E na linha 11 a 13, capturamos os dados que foram retornados da função lista_imagens(), e vamos adicionar a um arquivo JSON. Na linha 12, você precisa definir um bucket, para armazenar esse arquivo. Eu criei um outro bucket, para armazenar esse arquivo. E por último, precisamos criar um método main(), para informar ao Lambda, como os métodos serão executados, e em quais sequência.

Esse é o código que precisamos para fechar a execução do arquivo indexa.py. O único detalhe, você precisa definir na linha 2, o nome do bucket que você criou para armazenar as imagens. Na linha 3, temos uma função que vai capturar o nome do arquivo que você tiver fazendo o upload. Feito isso, basta seguir a sequência lógica de execução entre os métodos, e já teremos a primeira parte da aplicação construída. Antes de comentar a segunda parte, gostaria de apresentar como ficou a arquitetura da nossa aplicação até aqui.

Arquitetura da Função Lambda Indexa.py

Note que ao lado direito, o Lambda reconheceu que utilizamos o Rekognition, e o S3 em nossa aplicação. Do lado esquerdo, nós definimos um trigger (evento pré-requisito para execução da aplicação) do S3, dizendo que sempre que um objeto for criado, a nossa função pode ser executada. Veja como ficou a configuração dessa trigger:

Configuração da trigger S3.

Vamos agora à segunda parte da aplicação. Tenha em mente, que a partir de agora, estaremos trabalhando com outro script em Python. Dei o nome de pesquisa.py. Assim como no arquivo indexa.py, tivemos a integração entre a aplicação e o ElasticSearch, aqui também teremos. A configuração é exatamente a mesma. Portanto, não iremos repeti-la. Antes de passarmos para a próxima implementação, quero mostrar que de fato nossas dados estão sendo persistidos no ElasticSearch.

Descoberta de dados no Kibana.

Note que temos os dados persistidos corretamente no ElasticSearch. A imagem acima é do Kibana um serviço bem agradável para trabalhar com visualição e análise dos dados no ElasticSearch. Como verificamos que a primeira parte do trabalho está tudo ok, vamos então para a segunda parte, e garantir a pesquisa em nossa aplicação. Basicamente, teremos uma única função no arquivo pesquisa.py, que é para permitir buscas dentro do nosso índice no ElasticSearch.

Função para permitir busca no ElasticSearch em Python

Veja que a função acima é bem simples. Precisamos apenas ter a conexão com o ElasticSearch, no nosso caso, temos através do objeto esClient, e chamamos a função search(), passando os devidos parâmetros. Essa mesma busca, é feita no Kibana, ou em qualquer outra interface do ElasticSearch, a única diferença é que nessa aplicação, colocamos em Python, para que possamos posteriormente, converter essa função em um recurso de uma API Rest. A parte mais importante da função, está na linha 8, em informar qual será o parâmetro da pesquisa. Colocamos search, pois iremos definir esse parâmetro, na função main() do nosso arquivo no Lambda. O ElasticSearch utiliza uma sintaxe semelhante ao do Lucene para pesquisar dados, por exemplo para capturar dados entre duas categorias, podemos utilizar a cláusula OR ou AND:

Exemplo de sintaxe da pesquisa no ElasticSearch.

Veja acima, que estamos querendo pesquisar o que estiver dentro de labels, seja Coast ou Bird. Lembrando que labels, recebe um array dos objetos que foram detectados em cada uma das imagens que fizemos o upload. Para finalizar a nossa aplicação, temos o código da função main() dentro do AWS Lambda.

Note que na linha 3, capturamos o parâmetro de busca, dentro do evento de execução da função. Essa é uma forma de tornar a busca pelo ElasticSearch de forma dinâmica. Tendo feito isso, e iterado o resultado, para capturar apenas os valores que queremos, que é a o endereço da imagem no bucket, e a lista de valores dos objectos detectados. Finalizamos a segunda parte da aplicação. Para deixar a aplicação ainda mais profissional, podemos transformar o resultado dessa função de busca em uma API, utilizando o serviço de API Gateway. Para realizar a integração, é bem simples. Basta criar uma API, tendo o método GET, pois apenas utilizaremos consultas nessa API e definir a relação com a função do AWS Lambda criada. Feito isso, precisamos de algumas configurações, como definir uma Query String Parameters.

Parâmetros da query na API.

Veja que definimos para o nome do parâmetro, o mesmo nome que damos na função de execução do AWS Lambda. Precisamos definir também que o corpo da requisição será em formato JSON.

Configuração do corpo da requisiçao da API.

E por último, clicando nessa configuração que definimos (application/json), adicionaremos o seguinte código:

Parâmetros da API.

Gerando esse código acima, linkamos o parâmetro que criamos na execução da função no AWS Lambda, juntamente com o parâmetro que criamos dentro da API Gateway. Após essas configurações, podemos ir Actions e clicar para fazer o Deploy da API. Para verificar se está tudo certo, precisamos testar a nossa API. Você pode abrir um programa client, como o Postman e testar a requisição, ou você pode fazer isso diretamente pelo API Gateway.

Testando API de buscas.

Veja que nossa API está 100% funcional. Pesquisamos pelo termo coast, e ele encontrou em duas imagens. Incrível não é mesmo!? O que fizemos até aqui em nossa aplicaçao foi:

  • Listagem das imagens que temos no bucket S3. Salvamos isso num arquivo no formato JSON.
  • Upload de imagens, através de uma aplicação no AWS Lambda. Após o upload, automaticamente os dados são persistidos no ElasticSearch.
  • API Rest criada para permitir realizar a busca por objetos nas imagens que estão no S3.

Nosso trabalho com o Rekognition e ElasticSearch acabou por aí. A partir de agora, podemos criar uma especificaçao técnica do que foi desenvolvido e passar detalhes para uma equipe de desenvolvimento criar o frontend (interface) para essa aplicação. Eu criei uma aplicação web que serve de interface para essa nossa aplicação, embora não vá comentar sobre a arquitetura dessa aplicação, já que o artigo não é focado nisso, gostaria de compartilhar com vocês, algumas imagens e funcionalidades que extraímos do que foi criado aqui com o Rekognition e ElasticSearch.

Sobre a aplicação.

Nessa parte de sobre a aplicação, apenas compartilho um pouco sobre qual o propósito da aplicação, e algumas das tecnologias utilizadas. Na tela inicial, teremos a lista de imagens atualmente no bucket S3, e teremos a função de pesquisa também.

Tela inicial da aplicação.

Essa é a tela inicial da aplicação. Nessa tela, consumimos aquele arquivo JSON que geramos durante a aplicaçao que contem a lista das imagens que estão no bucket S3. Quando é clicado sobre cada uma das imagens, é aberto o endereço de cada imagem no bucket. Na parte superior a direita, adicionamos um campo de pesquisa para nossa aplicação. Esse componente de busca vai interagir com a nossa API, e assim conseguiremos realizar a busca pelos objetos nas imagens.

Busca pelo objeto coast.

Veja que o resultado da nossa busca pelo objeto coast, retornou duas imagens, como tínhamos visto no teste em nossa API. Cada uma dessas duas imagens (que são bem similares, inclusive), tiveram os seus cinco objetos detectados com uma precisão superior a 90%, e foram elas: Beach, Coast, Nature, Ocean, Outdoors. Muito legal, o trabalho que o algoritmo do Rekognition faz, não é mesmo? Gostaria de compartilhar um outro exemplo de busca.

Busca pelo objeto person.

Achei bem legal esse resultado :). Ele detectou o objeto person nessas três imagens. O detalhe, é que em uma dessas imagens, nós temos um jogo, o Donkey Kong Country, excelente jogo por sinal. Mas veja bem os objetos que foram detectados na imagem: Human, People, Person. Apesar do equívoco, vemos que o algoritmo tem grau de precisão muito alto. Na segunda imagem, por exemplo, além de detectar objetos, como Human, People, Person, também detectaram Football, Soccer. Por último, gostaria de mostrar também a funcionalidade de upload de imagens.

Upload de Imagens.

Adicionei uma nova foto pela aplicação, e automaticamente, já é atualizada na lista de imagens, e também na busca pelos objetos.

Nova listagem de imagens.
Nova busca pelo objeto person.

Agora é só brincar bastante com a aplicação, certeza que é diversão garantida!! Por último, gostaria de apresentar um bônus com o ElasticSearch. Imagine que você já possui uma aplicação como essa, e já tenha inúmeras imagens que foram armazenadas, e persistidas os objectos detectados em cada uma delas, que tal ter uma análise geral sobre quais objetos mais foram encontrados nas imagens, quantas imagens existem hoje na aplicação, dentre outras informações. A boa notícia é que podemos fazer isso, utilizando uma interface de análise dos dados com ElasticSearch, como o Kibana. E o melhor, ele já vem junto com o serviço ElasticSearch Service do Amazon AWS. Para finalizar, gostaria de apresentar alguns insights obtidos com visualizações dos nossos dados no Kibana.

Total de imagens no Kibana.
Total de objetos encontrados.

Aqui temos uma informação bem interessante. Apesar de nossa aplicação hoje, ter poucas imagens, se tivessem milhares, a análise seria muito perfomática, pois afinal, é para isso que serve o ElasticSearch aumentar bastante a perfomance de buscas em imagens. Nesse caso, vemos que há uma incidência maior dos objetos Human, People e Person, que dos objetos Beach e Coast, encontrado nas imagens. E caso seja necessário uma informação mais assertiva sobre a quantidade de objetos detectados, pode ser utilizado nesse caso, o gráfico de barras.

Total de objetos encontrados.

Legal essas informações, não é mesmo? Note que esse trabalho já está mais ligado à análise de dados. E sem dúvidas, o Kibana, facilita bastante esse trabalho para nós. Por último, você pode salvar cada umas dessas visualizações, e então organizar um dashboard com cada uma dessas informações.

Dashboard geral com as visualizações.

Se eu tivesse gerado novamente cada um desses dados, após a inserção de uma imagem que fizemos aqui na aplicação, certamente, teríamos uma alteração em cada uma das visualizações e do dashboard. Com isso, finalizamos o nosso artigo. Vimos algumas tecnologias bem interessantes. Espero que esse artigo possa ajudá-lo a começar a pensar na criação de aplicações em Visão Computacional. Ou até mesmo a utilizar o ElasticSearch em buscas de dados em alguma aplicação já existente. Até a próxima!

--

--

Rodrigo Macedo
Ensina.AI

Professor Informática EBTT IFMA | Estudande de Data Science, Cloud Computing e Inteligência Artificial.