Face detection e face recognition com ESP32-CAM

No artigo anterior apresentei o ESP32-CAM, essa belezinha da imagem de destaque do artigo anterior que, claro, provocou interesse imediato em muitos makers; muitos mesmo. Tanto, que publiquei o artigo em um domingo pela manhã e antes das 17:00 já havia sido vendidas todas as placas disponíveis no nosso parceiro MASUGUX. Mas não fique triste, você pode reservar a sua já para a próxima leva que deve chegar em menos de 30 dias e, realmente, recomendo que faça a reserva, porque vai acabar rápido de novo. Enquanto isso, veja como fazer face detection e face recognition com ESP32-CAM.

Diferença entre detection e recognition

Face detection é a capacidade de detectar um rosto, não importa quem seja; é a capacidade de saber diferenciar entre um rosto e uma batata, por exemplo.

Face recognition é o reconhecimento do rosto, sendo de uma pessoa devidamente cadastrada; é a capacidade de dizer se é “João” ou se é “José”.

O firmware utilizado nesse artigo é espetacular. Além de carregar um model para fazer o reconhecimento facial, ainda oferece uma interface web inacreditável, com montes de filtros!

No modo de operação padrão, a câmera captura frames de forma fluida. Já habilitando o face detection, a resolução deve ser CIF ou inferior. Isso não é um problema, é bastante comum utilizar imagens de 320×240 com foco em reconhecimento facial, mas no caso do ESP32-CAM, a degradação dos quadros é notória. Não é uma câmera para reconhecimento de transeuntes, mas para autenticação, abertura de portas, consulta de cadastro de clientes e coisas em que não haja realmente uma necessidade de resposta rápida, sim, é ideal e suficiente.

face recognition com ESP32-CAM

Onde comprar?

Para adquirir (quando disponível) ou reservar (se ainda indisponível), utilize esse link. Se quiser aproveitar, dê uma olhada na lista de produtos do MASUGUX.

Adicionar suporte ao ESP32 na IDE do Arduino

Sempre tem gente nova conhecendo o ESP32. Antes de ir para o Atom com PlatformIO, vou exemplificar a gravação de um ESP32-CAM utilizando a IDE do Arduino.

Copie o link abaixo  para incluir o suporte ao ESP32 à IDE do Arduino:

https://dl.espressif.com/dl/package_esp32_index.json

Agora abra a IDE do Arduino e siga o menu Arquivo > Preferências e coloque uma vírgula antes de colar o link no input box com as URLs de placas:

face recognition com ESP32-CAM

Alí na altura do cursor do mouse é onde se coloca a URL, não tem como errar.

Feito isso, feche e abra a IDE do Arduino novamente (estou tentando garantir que você consiga atingir o resultado de primeira). Vá ao menu Tools > Board > Board Manager e digite ESP32. Selecione a versão mais recente e clique em Install ou Update, caso já tenha o suporte ao ESP32 na IDE do Arduino.

Instalado? Ok, então reinicie a IDE do Arduino (lembre-se, estou fazendo isso para garantir que funcione de primeira. Reiniciando a interface você forçará a atualização dos repositórios de placas e bibliotecas, além do carregamento das placas e bibliotecas já instaladas).

O próximo passo é selecionar a placa correta.  No menu Tools > Boards selecione ESP32 Wrover Module.

Sketch too big

Se deixar no padrão, vai dar um estouro monstro de memória devido à área da flash reservado para OTA. Siga o menu Tools > Partition Scheme e mude para ficar igual abaixo:

face recognition com ESP32-CAM - memória

Com isso, o problema deve ser sanado. Agora o gran finale.

Gravar firmware no ESP32-CAM

Agora é a parte fácil. Com o suporte devidamente adicionado à IDE do Arduino e a placa selecionada corretamente, siga o menu File > Examples > ESP32 > Camera > CameraWebServer. Troque o SSID e senha para conectar o ESP32-CAM à sua rede.

Da linha 9 à 12, deixe desse jeito (definida a câmera AI_THINKER):

face recognition com ESP32-CAM - modelo

Mas antes de subir o firmware, você precisará (obviamente) conectar o ESP32-CAM ao computador.

Eu coloquei mais umas linhas pra ajudar depurar erros, uma vez que me deparei com alguns mas não tinha pistas. Nada de mais, apenas uns prints e delays nos  lugares certos. Você pode copiar e substituir o código padrão, se estiver ansioso por ver a câmera funcionando.

#include "esp_camera.h"
#include <WiFi.h>

//
// WARNING!!! Make sure that you have either selected ESP32 Wrover Module,
//            or another board which has PSRAM enabled
//

// Select camera model
//#define CAMERA_MODEL_WROVER_KIT
//#define CAMERA_MODEL_M5STACK_PSRAM
#define CAMERA_MODEL_AI_THINKER

const char* ssid = "SuhankoFamily";
const char* password = "fsjmr112";


#if defined(CAMERA_MODEL_WROVER_KIT)
#define PWDN_GPIO_NUM    -1
#define RESET_GPIO_NUM   -1
#define XCLK_GPIO_NUM    21
#define SIOD_GPIO_NUM    26
#define SIOC_GPIO_NUM    27

#define Y9_GPIO_NUM      35
#define Y8_GPIO_NUM      34
#define Y7_GPIO_NUM      39
#define Y6_GPIO_NUM      36
#define Y5_GPIO_NUM      19
#define Y4_GPIO_NUM      18
#define Y3_GPIO_NUM       5
#define Y2_GPIO_NUM       4
#define VSYNC_GPIO_NUM   25
#define HREF_GPIO_NUM    23
#define PCLK_GPIO_NUM    22

#elif defined(CAMERA_MODEL_M5STACK_PSRAM)
#define PWDN_GPIO_NUM     -1
#define RESET_GPIO_NUM    15
#define XCLK_GPIO_NUM     27
#define SIOD_GPIO_NUM     25
#define SIOC_GPIO_NUM     23

#define Y9_GPIO_NUM       19
#define Y8_GPIO_NUM       36
#define Y7_GPIO_NUM       18
#define Y6_GPIO_NUM       39
#define Y5_GPIO_NUM        5
#define Y4_GPIO_NUM       34
#define Y3_GPIO_NUM       35
#define Y2_GPIO_NUM       32
#define VSYNC_GPIO_NUM    22
#define HREF_GPIO_NUM     26
#define PCLK_GPIO_NUM     21

#elif defined(CAMERA_MODEL_AI_THINKER)
#define PWDN_GPIO_NUM     32
#define RESET_GPIO_NUM    -1
#define XCLK_GPIO_NUM      0
#define SIOD_GPIO_NUM     26
#define SIOC_GPIO_NUM     27

#define Y9_GPIO_NUM       35
#define Y8_GPIO_NUM       34
#define Y7_GPIO_NUM       39
#define Y6_GPIO_NUM       36
#define Y5_GPIO_NUM       21
#define Y4_GPIO_NUM       19
#define Y3_GPIO_NUM       18
#define Y2_GPIO_NUM        5
#define VSYNC_GPIO_NUM    25
#define HREF_GPIO_NUM     23
#define PCLK_GPIO_NUM     22

#else
#error "Camera model not selected"
#endif

void startCameraServer();

void setup() {
  Serial.begin(115200);
  Serial.setDebugOutput(true);
  Serial.println();
  delay(10000);
  Serial.println("Setting up...");

  camera_config_t config;
  config.ledc_channel = LEDC_CHANNEL_0;
  config.ledc_timer = LEDC_TIMER_0;
  config.pin_d0 = Y2_GPIO_NUM;
  config.pin_d1 = Y3_GPIO_NUM;
  config.pin_d2 = Y4_GPIO_NUM;
  config.pin_d3 = Y5_GPIO_NUM;
  config.pin_d4 = Y6_GPIO_NUM;
  config.pin_d5 = Y7_GPIO_NUM;
  config.pin_d6 = Y8_GPIO_NUM;
  config.pin_d7 = Y9_GPIO_NUM;
  config.pin_xclk = XCLK_GPIO_NUM;
  config.pin_pclk = PCLK_GPIO_NUM;
  config.pin_vsync = VSYNC_GPIO_NUM;
  config.pin_href = HREF_GPIO_NUM;
  config.pin_sscb_sda = SIOD_GPIO_NUM;
  config.pin_sscb_scl = SIOC_GPIO_NUM;
  config.pin_pwdn = PWDN_GPIO_NUM;
  config.pin_reset = RESET_GPIO_NUM;
  config.xclk_freq_hz = 20000000;
  config.pixel_format = PIXFORMAT_JPEG;
  //init with high specs to pre-allocate larger buffers
  if(psramFound()){
    config.frame_size = FRAMESIZE_UXGA;
    config.jpeg_quality = 10;
    config.fb_count = 2;
  } else {
    config.frame_size = FRAMESIZE_SVGA;
    config.jpeg_quality = 12;
    config.fb_count = 1;
  }

  // camera init
  esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK) {
    Serial.printf("Camera init failed with error 0x%x", err);
    return;
  }

  //drop down frame size for higher initial frame rate
  sensor_t * s = esp_camera_sensor_get();
  s->set_framesize(s, FRAMESIZE_QVGA);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");

  startCameraServer();

  Serial.print("Camera Ready! Use 'http://");
  Serial.print(WiFi.localIP());
  Serial.println("' to connect");
}

void loop() {
  // put your main code here, to run repeatedly:
  delay(10000);
  Serial.println("running...");
}

 

ESP32-CAM não tem porta USB?

Pois é. Não colocaram um conversor USB-serial nessa placa. Isso significa que você precisará de um FTDI para gravar o firmware. Não é um problema no final das contas, um FTDI pode ser utilizado em diversos casos, inclusive para fazer sniffing de uma comunicação serial.

O link para comprar FTDI é esse.

Tendo em mãos o FTDI, comece mantendo o ESP32-CAM desconectado do computador.

Se surgirem dúvidas quanto à explicação abaixo, leia o artigo anterior.

Coloque o TX do FTDI ao RX do ESP32-CAM e o RX do FTDI ao TX do ESP32-CAM. Alimente-o com o FTDI em 5V  (não faça c4g4d4, deixe o jumper do FTDI em 5V, coloque o VCC ao 5V do ESP32-CAM) e conecte o GND. Após, coloque um jumper fechando os pinos IO0 e GND. Estão lado a lado, pode ser um jumper de HD, não precisa ser um cabo com terminadores, mas se não tiver um jumper usado para wiring, use o cabinho mesmo.

face recognition com ESP32-CAM - ftdi

Seguindo o procedimento supracitado, conecte o FTDI ao computador, então mais uma vez, garanta que ele está em modo de gravação, apertando o botão RST que está do lado oposto do processador e câmera (na “costa” da placa). Ao apertar o botão RST, o LED utilizado para flash piscará.

Após subir o sketch, aparecerá nas mensagens da IDE do Arduino que foi feito reset da placa, mas o FTDI não está conectado para isso, portanto será necessário remover o jumper (sem problemas fazê-lo com a placa ligada) e apertar mais uma vez o botão RST. Abra então o terminal serial na IDE do Arduino e aguarde. Utilizando o código disposto acima você deverá ver algo como:

face recognition com ESP32-CAM - serial

Daí basta acessar pelo browser. No menu (exibido em uma imagem lá em cima) você pode iniciar a streaming da câmera ou pegar apenas uma amostra. No caso de amostra, pode ser útil para sistemas de cadastro.

Face detection com ESP32-CAM

No menu à esquerda da interface web, próximo ao rodapé, habilite o recurso face detection após mudar a resolução para CIF ou menor, no primeiro item desse mesmo menu. Um retângulo amarelo circundará qualquer face no campo de visão da câmera, como exibido na imagem mais acima. Como citado anteriormente, o fluxo de quadros reduzirá drasticamente, mas não é um problema, tudo depende da aplicação.

Face recognition com ESP32-CAM

Se habilitar o recurso de reconhecimento facial, faces desconhecidas serão tratadas como invasores. É um bom padrão, em minha humilde opinião.

face recognition com ESP32-CAM - alerta

Após cadastrar (clicando no botão Enroll face) o resultado deve ser algo como:

face recognition com ESP32-CAM - reconhecimento

A câmera está à esquerda do meu monitor principal, por isso as imagens estão sendo pegas de meio perfil. Após feito o reconhecimento, a acurácia foi incrivelmente alta, não gerando falso-positivo. Porém, é necessário cadastrar pelo menos uma família inteira no sistema para garantir que a inteligência artificial implantada é boa o suficiente.

A média de frames por segundo (monitorada no monitor serial) foi de 27fps. Com face detection ativado, a média é de 2fps, o que é bastante bom.

Um exemplo da saída da detecção na serial, mostrando inclusive o posicionamento da face:

MJPG: 9108B 1127ms (0.9fps), AVG: 985ms (1.0fps), 130+792+0+138=1061 DETECTED 0

E acredite ou não, para reconhecimento facial o tempo é similar, exceto em uma amostragem de pico que deu quase 8fps:

MJPG: 8995B 976ms (1.0fps), AVG: 133ms (7.5fps), 127+692+0+137=957 DETECTED 0
Match Face ID: 0

A primeira linha traz as informações relacionadas ao posicionamento e detecção da face, seguido por uma linha contendo o ID da face detectada. Daí basta cadastrar o ID em um sistema externo e fazer tudo o que imaginar com a informação.

Recém mudei de endereço, ainda estou iniciando a arrumação da minha estrutura de rede, mas vou tentar fazer entre hoje ou o mais breve possível um video de prova de conceito, se inscrevam lá no canal DobitAoByteBrasil no Youtube!

É, OMRON, a casa caiu. Bem-vindo ESP32-CAM!