Para isso terei que aprender várias coisas, portanto vamos por "baby steps"... Neste primeiro passo vamos ver como tirar uma foto e conseguir analisá-la.
A ideia de um auto-retrato parecia boa, mas a execução deixou a desejar |
As rotinas para interagir com a câmera estão em https://github.com/espressif/esp32-camera. Para começar a brincar precisamos:
- Preparar a configuração da câmera
- Iniciar a câmera através da função esp_camera_init()
- Solicitar a foto através da função esp_camera_fb_get()
- Processar a foto
- Devolver a área de memória recebida de esp_camera_fb_get() através de esp_camera_fb_return()
O programa abaixo faz isso. A configuração foi feita mesclando o exemplo no link acima como um exemplo do Randon Nerd Tutorials. O tamanho da foto está como VGA (640x480), porque o tamanho UXVGA (1600x1200) estourou a memória no próximo passo. O "processamento" é só mostrar o tempo para tirar a foto e o tamanho do arquivo.
#include "esp_camera.h" // Conexões da ESP32-CAM #define CAM_PIN_PWDN 32 #define CAM_PIN_RESET -1 // usar software reset #define CAM_PIN_XCLK 0 #define CAM_PIN_SIOD 26 #define CAM_PIN_SIOC 27 #define CAM_PIN_D7 35 #define CAM_PIN_D6 34 #define CAM_PIN_D5 39 #define CAM_PIN_D4 36 #define CAM_PIN_D3 21 #define CAM_PIN_D2 19 #define CAM_PIN_D1 18 #define CAM_PIN_D0 5 #define CAM_PIN_VSYNC 25 #define CAM_PIN_HREF 23 #define CAM_PIN_PCLK 22 // Configuração da camera static camera_config_t camera_config = { .pin_pwdn = CAM_PIN_PWDN, .pin_reset = CAM_PIN_RESET, .pin_xclk = CAM_PIN_XCLK, .pin_sscb_sda = CAM_PIN_SIOD, .pin_sscb_scl = CAM_PIN_SIOC, .pin_d7 = CAM_PIN_D7, .pin_d6 = CAM_PIN_D6, .pin_d5 = CAM_PIN_D5, .pin_d4 = CAM_PIN_D4, .pin_d3 = CAM_PIN_D3, .pin_d2 = CAM_PIN_D2, .pin_d1 = CAM_PIN_D1, .pin_d0 = CAM_PIN_D0, .pin_vsync = CAM_PIN_VSYNC, .pin_href = CAM_PIN_HREF, .pin_pclk = CAM_PIN_PCLK, .xclk_freq_hz = 20000000, .ledc_timer = LEDC_TIMER_0, .ledc_channel = LEDC_CHANNEL_0, .pixel_format = PIXFORMAT_JPEG, .frame_size = FRAMESIZE_VGA, .jpeg_quality = 12, //0-63 lower number means higher quality .fb_count = 1 //if more than one, i2s runs in continuous mode. Use only with JPEG }; // Iniciacao do programa void setup() { Serial.begin(115200); // Iniciar a camera esp_err_t err = esp_camera_init(&camera_config); if (err != ESP_OK) { Serial.print("Erro "); Serial.print (err); Serial.println (" ao iniciar a camera!"); // Não pode prosseguir for (;;) { delay (1000); } } } // Laço principal void loop() { // Tirar uma foto unsigned long inicio = millis(); camera_fb_t * fb = esp_camera_fb_get(); unsigned long fim = millis(); if (fb) { Serial.print ("Obteve foto, tempo = "); Serial.println (fim-inicio); Serial.print ("Tamanho = "); Serial.println (fb->len); esp_camera_fb_return(fb); } else { Serial.println ("Erro ao tirar a foto!"); } // Dá um tempo entre as fotos delay(3000); }
Como recomendado na biblioteca, o formato solicitado é JPG. Este formato implica em uma compressão, a perda de qualidade não é problema mas precisamos descompactar para acessarmos os pixels. Para isso existe a rotina jpg2bmp(). A notar que tanto esta rotina como esp_camera_fb_get() montam em memória exatamente uma imagem do arquivo, incluindo os respectivos cabeçalhos. Novamente a área retornada precisa ser liberada (nesta caso através de free).
Abaixo um outra versão da rotina loop() que gera o bmp e informa a resolução da foto.
Abaixo um outra versão da rotina loop() que gera o bmp e informa a resolução da foto.
// Estrutura do cabeçalho de arquivo BMP typedef struct { uint32_t filesize; uint32_t reserved; uint32_t fileoffset_to_pixelarray; uint32_t dibheadersize; int32_t width; int32_t height; uint16_t planes; uint16_t bitsperpixel; uint32_t compression; uint32_t imagesize; uint32_t ypixelpermeter; uint32_t xpixelpermeter; uint32_t numcolorspallette; uint32_t mostimpcolor; } bmp_header_t; // Laço principal com a conversão void loop() { // Dá um tempo entre as fotos delay(10000); // Tirar uma foto unsigned long inicio = millis(); camera_fb_t * fb = esp_camera_fb_get(); unsigned long fim = millis(); if (fb) { Serial.print ("Obteve foto, tempo = "); Serial.println (fim-inicio); Serial.print ("Tamanho = "); Serial.println (fb->len); uint8_t * buf = NULL; size_t buf_len = 0; inicio = millis(); bool converteu = frame2bmp(fb, &buf, &buf_len); fim = millis(); if (converteu) { Serial.print ("Converteu foto, tempo = "); Serial.println (fim-inicio); bmp_header_t * bitmap = (bmp_header_t*)&buf[2]; Serial.print ("Largura = "); Serial.println (bitmap->width); Serial.print ("Altura = "); Serial.println (-bitmap->height); free(buf); } else { Serial.println ("Erro na conversão!"); } esp_camera_fb_return(fb); } else { Serial.println ("Erro ao tirar a foto!"); } }
O próximo passo será comparar duas fotos para detectar movimento.
Um comentário:
Olá.
O meu deixa a primeira foto esverdeada e depois fica uma foto em defasagem... Se eu fizer a captura e pegar a segunda imagem fica perfeita, com uma qualidade top.
Outra dificuldade é quando está exposta ao sol, a minha gera nulos que não são codificados corretamente. (Já testou a sua na claridade do sol do meio dia?)
Postar um comentário