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