
Edge Impulse est une plateforme révolutionnaire conçue pour permettre aux développeurs de créer, optimiser et déployer directement les modèles d’apprentissage automatique sur les appareils IoT. En utilisant son interface intuitive et ses outils puissants, les développeurs peuvent collecter efficacement des données, entraîner des modèles et les intégrer dans des applications réelles, tout en bénéficiant du support robuste d’Edge Impulse pour différentes plates-formes matérielles et capteurs.

Code
/*
*Code de détection d’objet ESP32 cam
*par circuirdigest le 27 juin 2024
*/
#include // Modifier avec le titre de votre projet, Remplacez les xxxx
#include « edge-impulse-sdk/dsp/image/image.hpp »
#include « esp_camera.h »
// Sélection du modèle de caméra – trouver plus de modèles de caméra dans le fichier camera_pins.h ici
// https://github.com/espressif/arduino-esp32/blob/master/libraries/ESP32/…
// #define CAMERA_MODEL_ESP_EYE // A PSRAM
#define CAMERA_MODEL_AI_THINKER // A PSRAM
#if defined(CAMERA_MODEL_ESP_EYE)
#define PWDN_GPIO_NUM -1
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 4
#define SIOD_GPIO_NUM 18
#define SIOC_GPIO_NUM 23
#define Y9_GPIO_NUM 36
#define Y8_GPIO_NUM 37
#define Y7_GPIO_NUM 38
#define Y6_GPIO_NUM 39
#define Y5_GPIO_NUM 35
#define Y4_GPIO_NUM 14
#define Y3_GPIO_NUM 13
#define Y2_GPIO_NUM 34
#define VSYNC_GPIO_NUM 5
#define HREF_GPIO_NUM 27
#define PCLK_GPIO_NUM 25
#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 « Modèle de caméra non sélectionné »
#endif
/* Définitions de constantes——————————————————– */
#define EI_CAMERA_RAW_FRAME_BUFFER_COLS 320
#define EI_CAMERA_RAW_FRAME_BUFFER_ROWS 240
#define EI_CAMERA_FRAME_BYTE_SIZE 3
#include
#include
#include
// L’ESP32-CAM n’a pas de broches i2c dédiées, nous définissons donc les nôtres. Choisissons 15 et 14
#define I2C_SDA 15
#define I2C_SCL 14
TwoWire I2Cbus = TwoWire(0);
// Définit les paramètres de l’écran
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
#define SCREEN_ADDRESS 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &I2Cbus, OLED_RESET);
/* Variables privées ——————————————————- */
static bool debug_nn = false; // Définir à true pour voir par exemple les fonctionnalités générées à partir du signal brut
static bool is_initialised = false;
uint8_t *snapshot_buf; // pointe vers la sortie de la capture
static camera_config_t camera_config = {
.pin_pwdn = PWDN_GPIO_NUM,
.pin_reset = RESET_GPIO_NUM,
.pin_xclk = XCLK_GPIO_NUM,
.pin_sscb_sda = SIOD_GPIO_NUM,
.pin_sscb_scl = SIOC_GPIO_NUM,
.pin_d7 = Y9_GPIO_NUM,
.pin_d6 = Y8_GPIO_NUM,
.pin_d5 = Y7_GPIO_NUM,
.pin_d4 = Y6_GPIO_NUM,
.pin_d3 = Y5_GPIO_NUM,
.pin_d2 = Y4_GPIO_NUM,
.pin_d1 = Y3_GPIO_NUM,
.pin_d0 = Y2_GPIO_NUM,
.pin_vsync = VSYNC_GPIO_NUM,
.pin_href = HREF_GPIO_NUM,
.pin_pclk = PCLK_GPIO_NUM,
// XCLK 20MHz or 10MHz pour OV2640 double FPS (Expérimental)
.xclk_freq_hz = 20000000,
.ledc_timer = LEDC_TIMER_0,
.ledc_channel = LEDC_CHANNEL_0,
.pixel_format = PIXFORMAT_JPEG, // YUV422, NIVEAUX DE GRIS, RGB565, JPEG
.frame_size = FRAMESIZE_QVGA, // QQVGA-UXGA Ne pas utiliser de tailles supérieures à QVGA lorsque JPEG n’est pas utilisé
.jpeg_quality = 12, // 0-63 un chiffre plus bas signifie une meilleure qualité
.fb_count = 1, // si plus d’un, i2s fonctionne en mode continu. Utiliser uniquement avec JPEG
.fb_location = CAMERA_FB_IN_PSRAM,
.grab_mode = CAMERA_GRAB_WHEN_EMPTY,
};
/* Définitions de fonctions ——————————————————- */
bool ei_camera_init(void);
void ei_camera_deinit(void);
bool ei_camera_capture(uint32_t img_width, uint32_t img_height, uint8_t *out_buf);
/**
* @brief Fonction de configuration Arduino
*/
void setup() {
// mettez votre code de configuration ici, à exécuter une fois :
Serial.begin(115200);
// Initialiser l’I2C avec nos broches définies
I2Cbus.begin(I2C_SDA, I2C_SCL, 100000);
// SSD1306_SWITCHCAPVCC = générer une tension d’affichage à partir de 3,3V internes
if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
Serial.printf(« L’écran OLED SSD1306 n’a pas pu être initialisé.\nVérifiez que SDA de l’écran est connecté à la broche %d et SCL connecté à la broche %d\n », I2C_SDA, I2C_SCL);
while (true)
;
}
// commenter la ligne ci-dessous pour commencer l’inférence immédiatement après le téléchargement
while (!Serial)
;
Serial.println(« Démo d’inférence Edge Impulse »);
if (ei_camera_init() == false) {
ei_printf(« Échec de l’initialisation de la caméra !\r\n »);
} else {
ei_printf(« Caméra initialisée\r\n »);
}
ei_printf(« \nDémarrage de l’inférence continue dans 2 secondes…\n »);
display.clearDisplay();
display.setCursor(0, 0);
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.print(« Démarrage de l’inférence\n continue dans\n 2 secondes… »);
display.display();
ei_sleep(2000);
display.clearDisplay();
}
/**
* @brief Obtenir des données et exécuter l’inférence
*
* @param[in] debug Obtenez des informations de débogage si vrai
*/
void loop() {
display.clearDisplay();
// au lieu de wait_ms, nous attendrons le signal, cela permet aux threads de nous annuler…
if (ei_sleep(5) != EI_IMPULSE_OK) {
return;
}
snapshot_buf = (uint8_t *)malloc(EI_CAMERA_RAW_FRAME_BUFFER_COLS * EI_CAMERA_RAW_FRAME_BUFFER_ROWS * EI_CAMERA_FRAME_BYTE_SIZE);
// vérifier si l’allocation a réussi
if (snapshot_buf == nullptr) {
ei_printf(« ERR: Échec de l’allocation du tampon de capture !\n »);
return;
}
ei::signal_t signal;
signal.total_length = EI_CLASSIFIER_INPUT_WIDTH * EI_CLASSIFIER_INPUT_HEIGHT;
signal.get_data = &ei_camera_get_data;
if (ei_camera_capture((size_t)EI_CLASSIFIER_INPUT_WIDTH, (size_t)EI_CLASSIFIER_INPUT_HEIGHT, snapshot_buf) == false) {
ei_printf(« Échec de la capture de l’image\r\n »);
free(snapshot_buf);
return;
}
// Exécuter le classificateur
ei_impulse_result_t result = { 0 };
EI_IMPULSE_ERROR err = run_classifier(&signal, &result, debug_nn);
if (err != EI_IMPULSE_OK) {
ei_printf(« ERR: Échec de l’exécution du classificateur (%d)\n », err);
return;
}
// afficher les prédictions
ei_printf(« Prédictions (DSP: %d ms., Classification: %d ms., Anomalie: %d ms.) : \n »,
result.timing.dsp, result.timing.classification, result.timing.anomaly);
#if EI_CLASSIFIER_OBJECT_DETECTION == 1
bool bb_found = result.bounding_boxes[0].value > 0;
for (size_t ix = 0; ix < result.bounding_boxes_count; ix++) {
auto bb = result.bounding_boxes[ix];
if (bb.value == 0) {
continue;
}
ei_printf( » %s (%f) [ x: %u, y: %u, largeur: %u, hauteur: %u ]\n », bb.label, bb.value, bb.x, bb.y, bb.width, bb.height);
display.setCursor(0, 20 * ix);
display.setTextSize(2);
display.setTextColor(SSD1306_WHITE);
display.print(bb.label);
display.print(« -« );
display.print(int((bb.value)*100));
display.print(« % »);
display.display();
}
if (!bb_found) {
ei_printf( » Aucun objet trouvé\n »);
display.setCursor(0, 16);
display.setTextSize(2);
display.setTextColor(SSD1306_WHITE);
display.print(« Aucun objet trouvé »);
display.display();
}
#else
for (size_t ix = 0; ix < EI_CLASSIFIER_LABEL_COUNT; ix++) {
ei_printf( » %s: %.5f\n », result.classification[ix].label,
result.classification[ix].value);
}
#endif
#if EI_CLASSIFIER_HAS_ANOMALY == 1
ei_printf( » score d’anomalie: %.3f\n », result.anomaly);
#endif
free(snapshot_buf);
}
/**
* @brief Configuration du capteur d’image & démarrer le streaming
*
* @retval false si l’initialisation a échoué
*/
bool ei_camera_init(void) {
if (is_initialised) return true;
#if defined(CAMERA_MODEL_ESP_EYE)
pinMode(13, INPUT_PULLUP);
pinMode(14, INPUT_PULLUP);
#endif
//initialiser la caméra
esp_err_t err = esp_camera_init(&camera_config);
if (err != ESP_OK) {
Serial.printf(« Échec de l’initialisation de la caméra avec l’erreur 0x%x\n », err);
return false;
}
sensor_t *s = esp_camera_sensor_get();
// les capteurs initiaux sont retournés verticalement et les couleurs sont un peu saturées
if (s->id.PID == OV3660_PID) {
s->set_vflip(s, 1); // renverser
s->set_brightness(s, 1); // augmenter un peu la luminosité
s->set_saturation(s, 0); // diminuer la saturation
}
#if defined(CAMERA_MODEL_M5STACK_WIDE)
s->set_vflip(s, 1);
s->set_hmirror(s, 1);
#elif defined(CAMERA_MODEL_ESP_EYE)
s->set_vflip(s, 1);
s->set_hmirror(s, 1);
s->set_awb_gain(s, 1);
#endif
is_initialised = true;
return true;
}
/**
* @brief Arrêter le flux de données du capteur
*/
void ei_camera_deinit(void) {
//désinitialiser la caméra
esp_err_t err = esp_camera_deinit();
if (err != ESP_OK) {
ei_printf(« Échec de la désinitialisation de la caméra\n »);
return;
}
is_initialised = false;
return;
}
/**
* @brief Capturer, redimensionner et recadrer l’image
*
* @param[in] img_width largeur de l’image de sortie
* @param[in] img_height hauteur de l’image de sortie
* @param[in] out_buf pointeur pour stocker l’image de sortie, NULL peut être utilisé
* si ei_camera_frame_buffer doit être utilisé pour la capture et le redimensionnement/recadrage.
*
-
Heemol Pour cartes de développement ESP32-S3-CAM avec caméra OV3660, antenne 2,4 G + antenne IPEX, pour module ESP32-S3-N16R8 240 MHz, processeur double cœur, puce CH340 avec Wi-Fi, Bluetooth pour IoT
-
SunFounder Kit Ultime ESP32 (Compatible Arduino), ESP32-CAM, Conforme RoHS, Python, C, Scratch, Cours vidéo en Anglais, IoT pour débutants et ingénieurs, Carte ESP32 Board
