Reconhecimento Facial em Tempo Real no Navegador

Goran Jovanov Blocked Unblock Seguir Seguindo 10 de janeiro Facer

Não há muito tempo, Vincent Mühler postou vários posts sobre sua incrível biblioteca de reconhecimento facial face-api.js baseada no TensorFlowJS . Para mim, tendo trabalhado anteriormente com o OpenCV no lado do servidor, a ideia de fazer Face Recognition no navegador pareceu bastante complacente para experimentar. Como resultado dessa curiosidade, nasceu o Face® .

O Face® não é um projeto de IA, mas meramente um de engenharia, tentando utilizar o face-api.js para executar o Reconhecimento de Rosto no navegador e projetar uma solução de software que cuida de aspectos de aplicação como:

  • Registro do usuário
  • Modelos carregando
  • Upload de imagem, redimensionamento e exclusão
  • Usando a câmera (tirar e redimensionar fotos, reconhecimento de face)
  • Treinamento (extração de pontos de referência / descritores de rosto) e modelos de armazenamento
  • DevOps – Implantando usando o Docker

usando a seguinte pilha de tecnologia:

  • VueJS / NuxtJS / VuetifyJS – Frontend (simplesmente para ficar bem)
  • NodeJS / ExpressJS – Backend (conteúdo estático e manipuladores de API)
  • PM2 – Clustering (suporte a vários processos – um por núcleo da CPU)
  • Docker / Alpine Edge – Implantação (aplicativo contêiner enxuto)

Se você quiser saber mais sobre a biblioteca face-api.js, eu recomendo começar com a postagem de Vincent.

Aqui, nos concentraremos na criação de um aplicativo que utilize essa biblioteca.

Então vamos mergulhar nisso.

Modelos

Nós estaremos usando os seguintes modelos:

O tamanho total de todos os modelos é inferior a 6,5 MB.

Fluxo de trabalho de aplicativos

Por uma questão de simplicidade, este aplicativo não usará nenhum banco de dados como armazenamento por digitação e, em vez disso, o processo de registro de cada usuário dependerá de:

  • criando uma nova sub-pasta na pasta / dados / usuários / eg para o usuário Goran o aplicativo irá criar / data / users / Goran, no qual serão armazenadas todas as suas fotos necessárias para o treinamento do modelo de reconhecimento facial.
  • e um modelo de reconhecimento de rosto treinado para todos os usuários e todas as suas fotos serão armazenadas em um arquivo estático /data/faces.json (veja o formato abaixo).

Primeiro, o usuário precisará se cadastrar digitando seu nome, depois do qual ele precisa enviar pelo menos 3 fotos dele mesmo. O upload de fotos pode ser feito por upload de um arquivo ou por fotos usando a câmera do navegador (WebRTC getUserMedia API). Durante o upload, todas as fotos são redimensionadas para o tamanho 320×247 utilizando a imagem biblioteca de processamento de alto desempenho afiada .

Após o registro, o usuário pode iniciar o processo de treinamento , que leva todos os usuários do catálogo (e suas fotos enviadas) e extratos:

  • retângulos com seus rostos (opcional)
  • 68 marcos face (opcional)
  • 128 descritores de face (são necessários apenas para treinar o modelo)

e armazena o modelo de reconhecimento facial no arquivo estático /data/faces.json no seguinte formato:

Arquitetura

O aplicativo está usando o NUXT.JS com SSR (renderização no lado do servidor) e seguindo a convenção de estrutura de diretórios padrão.

O aplicativo no modo de desenvolvimento dividirá o SERVER em dois processos distintos:

  • /server/index.js – para conteúdo estático (frontend) – ouvindo na porta 3000
  • /api/index.js – para chamadas de API (backend) – ouvindo na porta 3001
 npm run dev 
npm run api

Ao separar o frontend do backend durante o desenvolvimento, estamos reduzindo o número de arquivos carregados pelo Nuxt e, com ele, o tamanho e a duração dessa inicialização inicial, além de nos beneficiarmos de um início / parada consecutivo mais rápido da API necessária durante depuração.

Por outro lado, no modo de produção , o aplicativo mescla o lado do servidor em um único processo, escutando na porta 3000.

 npm run build 
npm run start

Carregando os modelos

Quando o usuário acessar nosso aplicativo, carregaremos todos os modelos TensorflowJS e, para isso, utilizaremos o manipulador mounted () do /layouts/default.vue :

Com a ação load () sendo manipulada por /store/face.js :

Registro do usuário

Estamos registrando o usuário através do formulário simples na página /pages/users/index.vue manipulada pelo método register () :

Com a ação register () sendo manipulada pelo /store/user.js :

E a chamada da API sendo gerenciada pelo /api/controller/user-controller.js :

que cria uma nova pasta: / data / users / _name .

Upload de fotos

O usuário tem duas opções / guias para fazer upload de fotos:

  • tab-1 : Por um arquivo de upload de entrada HTML, manipulado pelo método filesChange () (redimensionado para 320×247 no lado do servidor)
  • Tab-2 : Ou usando a câmera do navegador (WebRTC getUserMedia API) e tirando instantâneos de fotos através da tela HTML5, manipulada pelo método takePhoto () (dimensionado para 320×247 no lado do cliente)

Após o registro, navegamos pelo usuário na página em que ele pode continuar fazendo o upload de fotos /pages/users/_name.vue.

Com as ações upload () e uploadBase64 () sendo manipuladas pelo /store/user.js :

E as chamadas de API sendo tratadas pelo /api/controller/user-controller.js :

Para extrair o conteúdo do arquivo dos dados mutipart / form , estamos usando Multer . Além disso, como o usuário pode fazer upload de imagens de diferentes tamanhos e formas, estamos redimensionando a imagem enviada usando a nitidez . Finalmente, as fotos são armazenadas na pasta do usuário: / data / users / _name / .

Treinamento – Exraction de Descritor de Face

Treinamento é o processo de extrair 128 descritores de face de uma imagem para um determinado usuário (vetor de 128 valores de descritor).

Recomenda-se que um usuário tenha pelo menos três fotos enviadas para treinamento. Assim, após o treinamento, o modelo de reconhecimento de faces será composto de vetores descritores n x m ; m – sendo o número de usuários e n – sendo o número de fotos para determinado usuário.

Podemos realizar treinamento de uma das seguintes maneiras:

  • Um por um – treinando após cada upload de foto de um usuário selecionado
  • Por usuário – treinamento para todas as fotos do usuário de um usuário selecionado
  • Lote – treinamento para todos os usuários e todas as suas fotos de uma só vez

Neste aplicativo, implementaremos um processo de treinamento em lote que, como resultado final, armazenará o modelo de rechamada de rosto dentro do arquivo /data/faces.json .

O processo de treinamento em lote é iniciado a partir do /pages/train.vue :

que percorre a lista de usuários e, para cada uma de suas fotos, extrai os descritores de face (vetor descritor de face de 128). Depois disso, salve o modelo de reconhecimento de face JSON por meio da ação save () do /store/face.js :

E a chamada da API sendo manipulada por /api/controllers/face-controller.js :

Reconhecimento

O processo de reconhecimento facial lê o modelo de reconhecimento facial (faces.json) e cria um Face Matcher , que é capaz de calcular a Distância Euclidiana entre os vetores descritores faciais do modelo de reconhecimento de rosto armazenado e qualquer nova face a ser reconhecida.

Na interface do usuário, através da câmera (WebRTC getUserMedia API), começamos a amostra com 60 fps (quadros por segundo) instantâneo armazenado dentro de um elemento de tela HTML. Então, para cada snapshot, extraímos seus descritores de face e, usando o matcher de face, geramos a melhor correspondência e a recolocamos na tela.

O processo de reconhecimento facial é iniciado através do /pages/recognize.vue :

onde as ações getFaceDetections () , drawLandmarks () , recognise () e drawDetections () são manipuladas por /store/face.js :

Produção

Como o NodeJS, por padrão, funciona em um único processo, na produção, essa abordagem não é a ideal, especialmente se tivermos hardware com CPUs múltiplas e / ou Núcleos de CPU.

Portanto, utilizaremos o PM2 para instanciar o número de núcleos de CPU que temos (-i 0 param) e balancear a carga entre os processos bifurcados:

 pm2 start server / index.js -i 0 - anexar 

Implantar

Nós empacotamos nosso aplicativo como uma Docker Image muito enxuta, com base no Alpine: Edge (menos de 300 MB porque o tamanho é importante):

Então nós podemos:

  • crie a imagem do Docker pelo docker build -t gjovanov/facer .
  • ou use o script de versionamento do Travis Reeder ./build.sh

Ou puxe o do Docker Hub docker pull gjovanov/facer .

Finalmente, podemos executar o contêiner Docker por:

 docker run -d --name facer  
--hostname facer
--restart always
-e API_URL=https://facer.xplorify.net
-p 8081:3000
-v /gjovanov/facer/data:/facer/data
--net=bridge
gjovanov/facer

Código-fonte e demonstração

Ambos, o código fonte e uma demonstração estão disponíveis para experimentar.

Todas as sugestões de melhorias ou solicitações pull são mais que bem-vindas.