Ce référentiel héberge le pilote compatible SOC de la série ESP32 pour les capteurs d'image. De plus, il fournit quelques outils, qui permettent de convertir les données de trame capturées en formats BMP et JPEG les plus courants.
modèle | Résolution maximale | type de couleur | format de sortie | Tailler |
---|---|---|---|---|
OV2640 | 1600 x 1200 | couleur | YUV (422/420) / YCBCR422 RGB565 / 555 Données compressées à 8 bits Données RVB brutes 8/10 bits | 1/4 " |
OV3660 | 2048 x 1536 | couleur | Données RVB brutes RGB565 / 555/444 CCIR656 Ycbcr422 compression | 1/5 " |
OV5640 | 2592 x 1944 | couleur | RVB brut RGB565 / 555/444 CCIR656 YUV422 / 420 Ycbcr422 compression | 1/4 " |
OV7670 | 640 x 480 | couleur | Raw Bayer RVB Bayer RVB transformé Yuv / ycbcr422 Grb422 RGB565 / 555 | 1/6 " |
OV7725 | 640 x 480 | couleur | RVB brut Grb 422 RGB565 / 555/444 YCBCR 422 | 1/4 " |
NT99141 | 1280 x 720 | couleur | YCBCR 422 RGB565 / 555/444 Brut CCIR656 Compression jpeg | 1/4 " |
GC032A | 640 x 480 | couleur | Yuv / ycbcr422 Bayer brut RGB565 | 1/10 " |
GC0308 | 640 x 480 | couleur | Yuv / ycbcr422 Bayer brut RGB565 Niveaux de gris | 1 / 6,5 " |
GC2145 | 1600 x 1200 | couleur | Yuv / ycbcr422 Bayer brut RGB565 | 1/5 " |
BF3005 | 640 x 480 | couleur | Yuv / ycbcr422 Bayer brut RGB565 | 1/4 " |
BF20A6 | 640 x 480 | couleur | Yuv / ycbcr422 Bayer brut Seulement y | 1/10 " |
Sc101iot | 1280 x 720 | couleur | Yuv / ycbcr422 RVB brut | 1/4,2 " |
SC030iot | 640 x 480 | couleur | Yuv / ycbcr422 Bayer brut | 1 / 6,5 " |
SC031GS | 640 x 480 | monochrome | Mono brut Niveaux de gris | 1/6 " |
fmt2rgb888
ou fmt2bmp
/ frame2bmp
.espressif/esp32-camera
: idf.py add-dependency " espressif/esp32-camera "
menuconfig
(définissez également les fréquences Flash et PSRAM à 80 MHz)esp_camera.h
dans votre code Ces instructions fonctionnent également pour PlatformoIo, si vous utilisez framework=espidf
.
Si vous utilisez le noyau Arduino-ESP32 dans Arduino IDE, aucune installation n'est nécessaire! Vous pouvez utiliser immédiatement ESP32-caméra.
La manière facile - sur la section env
de platformio.ini
, ajoutez ce qui suit:
[env]
lib_deps =
esp32-camera
Maintenant, l' esp_camera.h
est disponible pour être inclus:
#include "esp_camera.h"
Activez PSRAM sur menuconfig
ou tapez-le Direclty sur sdkconfig
. Consultez le Doc officiel pour plus d'informations.
CONFIG_ESP32_SPIRAM_SUPPORT=y
Ce composant est livré avec un exemple de base illustrant comment obtenir des cadres de la caméra. Vous pouvez essayer l'exemple en utilisant la commande suivante:
idf.py create-project-from-example "espressif/esp32-camera:camera_example"
Cette commande téléchargera l'exemple dans le répertoire camera_example
. Il vient déjà préconfiguré avec les paramètres corrects dans 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 ;
}