Este repositorio aloja un controlador compatible con SoC de la serie ESP32 para sensores de imagen. Además, proporciona algunas herramientas, que permiten convertir los datos del marco capturados en los formatos BMP y JPEG más comunes.
modelo | resolución máxima | tipo de color | formato de salida | Tamaño de la lista |
---|---|---|---|---|
Ov2640 | 1600 x 1200 | color | YUV (422/420)/YCBCR422 RGB565/555 Datos comprimidos de 8 bits Datos de RGB sin procesar de 8/10 bits | 1/4 " |
Ov3660 | 2048 x 1536 | color | Datos de RGB sin procesar RGB565/555/444 CCIR656 YCBCR422 compresión | 1/5 " |
Ov5640 | 2592 x 1944 | color | RGB en bruto RGB565/555/444 CCIR656 YUV422/420 YCBCR422 compresión | 1/4 " |
Ov7670 | 640 x 480 | color | Raw Bayer RGB Bayer RGB procesado YUV/YCBCR422 GRB422 RGB565/555 | 1/6 " |
Ov7725 | 640 x 480 | color | RGB en bruto GRB 422 RGB565/555/444 YCBCR 422 | 1/4 " |
NT99141 | 1280 x 720 | color | YCBCR 422 RGB565/555/444 Crudo CCIR656 Compresión jpeg | 1/4 " |
GC032A | 640 x 480 | color | YUV/YCBCR422 Bayer crudo RGB565 | 1/10 " |
GC0308 | 640 x 480 | color | YUV/YCBCR422 Bayer crudo RGB565 Escala de grises | 1/6.5 " |
GC2145 | 1600 x 1200 | color | YUV/YCBCR422 Bayer crudo RGB565 | 1/5 " |
BF3005 | 640 x 480 | color | YUV/YCBCR422 Bayer crudo RGB565 | 1/4 " |
BF20A6 | 640 x 480 | color | YUV/YCBCR422 Bayer crudo Solo y | 1/10 " |
Sc101iot | 1280 x 720 | color | YUV/YCBCR422 RGB en bruto | 1/4.2 " |
Sc030iot | 640 x 480 | color | YUV/YCBCR422 Bayer crudo | 1/6.5 " |
SC031GS | 640 x 480 | monocromo | Mono crudo Escala de grises | 1/6 " |
fmt2rgb888
o fmt2bmp
/ frame2bmp
.espressif/esp32-camera
: idf.py add-dependency " espressif/esp32-camera "
menuconfig
(también establezca frecuencias Flash y PSRAM a 80MHz)esp_camera.h
en su código Estas instrucciones también funcionan para Platformio, si está utilizando framework=espidf
.
Si está utilizando el núcleo Arduino-ESP32 en Arduino IDE, ¡no se necesita instalación! Puedes usar ESP32-Camera de inmediato.
La manera fácil: en la sección env
de platformio.ini
, agregue lo siguiente:
[env]
lib_deps =
esp32-camera
Ahora el esp_camera.h
está disponible para ser incluido:
#include "esp_camera.h"
Habilite PSRAM en menuconfig
o escriba directamente en sdkconfig
. Consulte el documento oficial para obtener más información.
CONFIG_ESP32_SPIRAM_SUPPORT=y
Este componente viene con un ejemplo básico que ilustra cómo obtener marcos de la cámara. Puede probar el ejemplo usando el siguiente comando:
idf.py create-project-from-example "espressif/esp32-camera:camera_example"
Este comando descargará el ejemplo en el directorio camera_example
. Ya viene preconfigurado con la configuración correcta en Menuconfig.
#include "esp_camera.h"
//WROVER-KIT PIN Map
#define CAM_PIN_PWDN -1 //power down is not used
#define CAM_PIN_RESET -1 //software reset will be performed
#define CAM_PIN_XCLK 21
#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 19
#define CAM_PIN_D2 18
#define CAM_PIN_D1 5
#define CAM_PIN_D0 4
#define CAM_PIN_VSYNC 25
#define CAM_PIN_HREF 23
#define CAM_PIN_PCLK 22
static camera_config_t camera_config = {
. pin_pwdn = CAM_PIN_PWDN ,
. pin_reset = CAM_PIN_RESET ,
. pin_xclk = CAM_PIN_XCLK ,
. pin_sccb_sda = CAM_PIN_SIOD ,
. pin_sccb_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 , //EXPERIMENTAL: Set to 16MHz on ESP32-S2 or ESP32-S3 to enable EDMA mode
. ledc_timer = LEDC_TIMER_0 ,
. ledc_channel = LEDC_CHANNEL_0 ,
. pixel_format = PIXFORMAT_JPEG , //YUV422,GRAYSCALE,RGB565,JPEG
. frame_size = FRAMESIZE_UXGA , //QQVGA-UXGA, For ESP32, do not use sizes above QVGA when not JPEG. The performance of the ESP32-S series has improved a lot, but JPEG mode always gives better frame rates.
. jpeg_quality = 12 , //0-63, for OV series camera sensors, lower number means higher quality
. fb_count = 1 , //When jpeg mode is used, if fb_count more than one, the driver will work in continuous mode.
. grab_mode = CAMERA_GRAB_WHEN_EMPTY //CAMERA_GRAB_LATEST. Sets when buffers should be filled
};
esp_err_t camera_init (){
//power up the camera if PWDN pin is defined
if ( CAM_PIN_PWDN != -1 ){
pinMode ( CAM_PIN_PWDN , OUTPUT );
digitalWrite ( CAM_PIN_PWDN , LOW );
}
//initialize the camera
esp_err_t err = esp_camera_init ( & camera_config );
if ( err != ESP_OK ) {
ESP_LOGE ( TAG , "Camera Init Failed" );
return err ;
}
return ESP_OK ;
}
esp_err_t camera_capture (){
//acquire a frame
camera_fb_t * fb = esp_camera_fb_get ();
if (! fb ) {
ESP_LOGE ( TAG , "Camera Capture Failed" );
return ESP_FAIL ;
}
//replace this with your own function
process_image ( fb -> width , fb -> height , fb -> format , fb -> buf , fb -> len );
//return the frame buffer back to the driver for reuse
esp_camera_fb_return ( fb );
return ESP_OK ;
}
#include "esp_camera.h"
#include "esp_http_server.h"
#include "esp_timer.h"
typedef struct {
httpd_req_t * req ;
size_t len ;
} jpg_chunking_t ;
static size_t jpg_encode_stream ( void * arg , size_t index , const void * data , size_t len ){
jpg_chunking_t * j = ( jpg_chunking_t * ) arg ;
if (! index ){
j -> len = 0 ;
}
if ( httpd_resp_send_chunk ( j -> req , ( const char * ) data , len ) != ESP_OK ){
return 0 ;
}
j -> len += len ;
return len ;
}
esp_err_t jpg_httpd_handler ( httpd_req_t * req ){
camera_fb_t * fb = NULL ;
esp_err_t res = ESP_OK ;
size_t fb_len = 0 ;
int64_t fr_start = esp_timer_get_time ();
fb = esp_camera_fb_get ();
if (! fb ) {
ESP_LOGE ( TAG , "Camera capture failed" );
httpd_resp_send_500 ( req );
return ESP_FAIL ;
}
res = httpd_resp_set_type ( req , "image/jpeg" );
if ( res == ESP_OK ){
res = httpd_resp_set_hdr ( req , "Content-Disposition" , "inline; filename=capture.jpg" );
}
if ( res == ESP_OK ){
if ( fb -> format == PIXFORMAT_JPEG ){
fb_len = fb -> len ;
res = httpd_resp_send ( req , ( const char * ) fb -> buf , fb -> len );
} else {
jpg_chunking_t jchunk = { req , 0 };
res = frame2jpg_cb ( fb , 80 , jpg_encode_stream , & jchunk )? ESP_OK : ESP_FAIL ;
httpd_resp_send_chunk ( req , NULL , 0 );
fb_len = jchunk . len ;
}
}
esp_camera_fb_return ( fb );
int64_t fr_end = esp_timer_get_time ();
ESP_LOGI ( TAG , "JPG: %uKB %ums" , ( uint32_t )( fb_len / 1024 ), ( uint32_t )(( fr_end - fr_start )/ 1000 ));
return res ;
}
#include "esp_camera.h"
#include "esp_http_server.h"
#include "esp_timer.h"
#define PART_BOUNDARY "123456789000000000000987654321"
static const char * _STREAM_CONTENT_TYPE = "multipart/x-mixed-replace;boundary=" PART_BOUNDARY ;
static const char * _STREAM_BOUNDARY = "rn--" PART_BOUNDARY "rn" ;
static const char * _STREAM_PART = "Content-Type: image/jpegrnContent-Length: %urnrn" ;
esp_err_t jpg_stream_httpd_handler ( httpd_req_t * req ){
camera_fb_t * fb = NULL ;
esp_err_t res = ESP_OK ;
size_t _jpg_buf_len ;
uint8_t * _jpg_buf ;
char * part_buf [ 64 ];
static int64_t last_frame = 0 ;
if (! last_frame ) {
last_frame = esp_timer_get_time ();
}
res = httpd_resp_set_type ( req , _STREAM_CONTENT_TYPE );
if ( res != ESP_OK ){
return res ;
}
while (true){
fb = esp_camera_fb_get ();
if (! fb ) {
ESP_LOGE ( TAG , "Camera capture failed" );
res = ESP_FAIL ;
break ;
}
if ( fb -> format != PIXFORMAT_JPEG ){
bool jpeg_converted = frame2jpg ( fb , 80 , & _jpg_buf , & _jpg_buf_len );
if (! jpeg_converted ){
ESP_LOGE ( TAG , "JPEG compression failed" );
esp_camera_fb_return ( fb );
res = ESP_FAIL ;
}
} else {
_jpg_buf_len = fb -> len ;
_jpg_buf = fb -> buf ;
}
if ( res == ESP_OK ){
res = httpd_resp_send_chunk ( req , _STREAM_BOUNDARY , strlen ( _STREAM_BOUNDARY ));
}
if ( res == ESP_OK ){
size_t hlen = snprintf (( char * ) part_buf , 64 , _STREAM_PART , _jpg_buf_len );
res = httpd_resp_send_chunk ( req , ( const char * ) part_buf , hlen );
}
if ( res == ESP_OK ){
res = httpd_resp_send_chunk ( req , ( const char * ) _jpg_buf , _jpg_buf_len );
}
if ( fb -> format != PIXFORMAT_JPEG ){
free ( _jpg_buf );
}
esp_camera_fb_return ( fb );
if ( res != ESP_OK ){
break ;
}
int64_t fr_end = esp_timer_get_time ();
int64_t frame_time = fr_end - last_frame ;
last_frame = fr_end ;
frame_time /= 1000 ;
ESP_LOGI ( TAG , "MJPG: %uKB %ums (%.1ffps)" ,
( uint32_t )( _jpg_buf_len / 1024 ),
( uint32_t ) frame_time , 1000.0 / ( uint32_t ) frame_time );
}
last_frame = 0 ;
return res ;
}
#include "esp_camera.h"
#include "esp_http_server.h"
#include "esp_timer.h"
esp_err_t bmp_httpd_handler ( httpd_req_t * req ){
camera_fb_t * fb = NULL ;
esp_err_t res = ESP_OK ;
int64_t fr_start = esp_timer_get_time ();
fb = esp_camera_fb_get ();
if (! fb ) {
ESP_LOGE ( TAG , "Camera capture failed" );
httpd_resp_send_500 ( req );
return ESP_FAIL ;
}
uint8_t * buf = NULL ;
size_t buf_len = 0 ;
bool converted = frame2bmp ( fb , & buf , & buf_len );
esp_camera_fb_return ( fb );
if (! converted ){
ESP_LOGE ( TAG , "BMP conversion failed" );
httpd_resp_send_500 ( req );
return ESP_FAIL ;
}
res = httpd_resp_set_type ( req , "image/x-windows-bmp" )
|| httpd_resp_set_hdr ( req , "Content-Disposition" , "inline; filename=capture.bmp" )
|| httpd_resp_send ( req , ( const char * ) buf , buf_len );
free ( buf );
int64_t fr_end = esp_timer_get_time ();
ESP_LOGI ( TAG , "BMP: %uKB %ums" , ( uint32_t )( buf_len / 1024 ), ( uint32_t )(( fr_end - fr_start )/ 1000 ));
return res ;
}