Questions about esp32cam

Hey,

I'm doing some tests with esp32cam. The latest one is about facial recognition.

Let's say I have a 2Gb card. And using only esp32cam AI Thinker. How many faces can I record?

And if by some bad luck the esp32cam crashes, but without damaging the memory card, can I insert the same memory card into another esp32cam and the saved faces will be there?

Thanks

Record one face and take note of the amount of SD memory required. Divide that into the total free SD memory.

saved faces will be there?

Try it and let us know.

Let's hope someone who knows wants to help with answers. Watch out too.

In the CameraWebServer example there is a warning:

Face Recognition takes upward from 15 seconds per frame on chips other than ESP32S3. Makes no sense to have it enabled for them.

Depends entirely on the resolution you select for the pictures taken.

Let's say it's in a VGA resolution, how many faces can I record in 2 Gb?

Why is this so difficult for you, that you need to post such a question on the Arduino forum?

Well since you are doing tests with an ESP32CAM, you could take a picture at VGA resolution and then check how much space it takes on the SD.

lol, of course I can do that, I haven't mounted anything yet, I just had these two questions. There are maybe hundreds of people here who maybe have done tests before me and tests much deeper. There would be just two naive answers: A) About 400 faces in VGA. B) Yes, you can use the SD card as a backup in another identical esp32cam.

It was just that. But I understand that the posts here generate controversy.

But it's good. Everyone writes what they want.

Let's hope it will be read by more people.

My apologies, I had assumed you had it connected since you said;

"I'm doing some tests with esp32cam"

Don't apologize in vain.

The fact that you thought that doesn't make you guilty of anything.

With a little effort you can get an estimate of what you want to know all by yourself ... without even having to try it with the SD card. You already know (or can find out) the size of an image (in bytes) taken by the camera. Divide that into the capacity of the SD card. Try it with a couple pictures having different content.

That would probably be an extreme lower bound on the number of faces you can save on the SD card. You can get an even better estimate by looking through the source code of the facial recognition functions to see how faces are stored. I'll bet it's in a much smaller structure than is occupied by a full frame buffer.

Yes, everything can be done, also ask, do you remember how your life was up until now? non-stop questions, you will always ask questions. There is nothing wrong with that.

That is way too much trouble for the OP. Spoon feeding seems to be required.

So do it. Or at least attempt it.

Few people are interested in helping someone who shows no initiative to solve there own problem. So far the only effort you seem to have put in is typing up a question for someone else to answer. Show us what you have done to solve your problem.

About a GB of faces could be stored on the 2GB sd card for some card longevity. Card longevity begins to rapidly drop off when the card is about 1/2 full or more. Wear leveling is impacted by using more than 50% of the cards capacity.

Hope this helps,

Let us know what numbers you come up with.

It's not the case. For those who can read, it's more like someone who is thinking about studying a car, and asks a club of people: Has anyone had this car? Do you know how many liters per kilometer? Its confortable ? etc.

Here comes some and they answer: Buy one and you will have all these answers. Strive.

It's not the case. I only asked two questions, and to your chagrin I always will.

But you, and anyone else who feels hurt, can be smarter and do like many who read my questions and are already out there, didn't even answer. It's simple.

Why type so much.

1 Like

This code recognizes faces and assigns them a value shown on the serial monitor (new name : 5853918325)

#include "Arduino.h"
#include <esp_int_wdt.h>
#include <esp_task_wdt.h>
#include "soc/soc.h" //disable brownout problems
#include "soc/rtc_cntl_reg.h"  //disable brownout problems
#include "esp_camera.h"
#include "fd_forward.h"
#include "fr_forward.h"
#include "fr_flash.h"
#include "FS.h"
#include "SD_MMC.h"

#define 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

static inline mtmn_config_t app_mtmn_config()
{
  mtmn_config_t mtmn_config = {0};
  mtmn_config.type = FAST;
  mtmn_config.min_face = 80;
  mtmn_config.pyramid = 0.707;
  mtmn_config.pyramid_times = 4;
  mtmn_config.p_threshold.score = 0.6;
  mtmn_config.p_threshold.nms = 0.7;
  mtmn_config.p_threshold.candidate_number = 20;
  mtmn_config.r_threshold.score = 0.7;
  mtmn_config.r_threshold.nms = 0.7;
  mtmn_config.r_threshold.candidate_number = 10;
  mtmn_config.o_threshold.score = 0.7;
  mtmn_config.o_threshold.nms = 0.7;
  mtmn_config.o_threshold.candidate_number = 1;
  return mtmn_config;
}

#define ENROLL_CONFIRM_TIMES 6
#define FACE_ID_SAVE_NUMBER 99

face_id_name_list st_face_list;
mtmn_config_t mtmn_config = {0};
dl_matrix3du_t *aligned_face = NULL;
bool enrolling = false;
int nb_enroll = 0;

const int length = 10;
char new_name[length+1]; // this var will contain generated names for enrolled faces


void init_cam(){

  camera_config_t config;
  config.ledc_channel = LEDC_CHANNEL_0;
  config.ledc_timer = LEDC_TIMER_0;
  config.pin_d0 = Y2_GPIO_NUM;
  config.pin_d1 = Y3_GPIO_NUM;
  config.pin_d2 = Y4_GPIO_NUM;
  config.pin_d3 = Y5_GPIO_NUM;
  config.pin_d4 = Y6_GPIO_NUM;
  config.pin_d5 = Y7_GPIO_NUM;
  config.pin_d6 = Y8_GPIO_NUM;
  config.pin_d7 = Y9_GPIO_NUM;
  config.pin_xclk = XCLK_GPIO_NUM;
  config.pin_pclk = PCLK_GPIO_NUM;
  config.pin_vsync = VSYNC_GPIO_NUM;
  config.pin_href = HREF_GPIO_NUM;
  config.pin_sscb_sda = SIOD_GPIO_NUM;
  config.pin_sscb_scl = SIOC_GPIO_NUM;
  config.pin_pwdn = PWDN_GPIO_NUM;
  config.pin_reset = RESET_GPIO_NUM;
  config.xclk_freq_hz = 10000000;
  config.pixel_format = PIXFORMAT_JPEG;
  //init with high specs to pre-allocate larger buffers
  if (psramFound()) {
    config.frame_size = FRAMESIZE_UXGA;
    config.jpeg_quality = 10;
    config.fb_count = 2;
  } else {
    config.frame_size = FRAMESIZE_SVGA;
    config.jpeg_quality = 12;
    config.fb_count = 1;
  }

  // camera init
  esp_err_t err = esp_camera_init(&config);

  if (err != ESP_OK) {
    delay(100);  // need a delay here or the next serial o/p gets missed
    Serial.printf("\n\nCRITICAL FAILURE: Camera sensor failed to initialise.\n\n");
    Serial.printf("A full (hard, power off/on) reboot will probably be needed to recover from this.\n");
    Serial.printf("Meanwhile; this unit will reboot in 1 minute since these errors sometime clear automatically\n");
    // Reset the I2C bus.. may help when rebooting.
    periph_module_disable(PERIPH_I2C0_MODULE); // try to shut I2C down properly in case that is the problem
    periph_module_disable(PERIPH_I2C1_MODULE);
    periph_module_reset(PERIPH_I2C0_MODULE);
    periph_module_reset(PERIPH_I2C1_MODULE);
    // And set the error text for the UI
    Serial.println("Error! \nCamera module failed to initialise!\nPlease reset (power off/on) the camera");
    Serial.println("We will continue to reboot once per minute since this error sometimes clears automatically");
    // Start a 60 second watchdog timer
    esp_task_wdt_init(60,true);
    esp_task_wdt_add(NULL);
  } else {
    Serial.println("Camera init succeeded");

    // Get a reference to the sensor
    sensor_t * s = esp_camera_sensor_get();

    // Dump camera module, warn for unsupported modules.
    switch (s->id.PID) {
      case OV9650_PID: Serial.println("WARNING: OV9650 camera module is not properly supported, will fallback to OV2640 operation"); break;
      case OV7725_PID: Serial.println("WARNING: OV7725 camera module is not properly supported, will fallback to OV2640 operation"); break;
      case OV2640_PID: Serial.println("OV2640 camera module detected"); break;
      case OV3660_PID: Serial.println("OV3660 camera module detected"); break;
      default: Serial.println("WARNING: Camera module is unknown and not properly supported, will fallback to OV2640 operation");
    }
    //initial sensors are flipped vertically and colors are a bit saturated
    //drop down frame size for higher initial frame rate
    s->set_framesize(s, FRAMESIZE_QVGA);
    s->set_quality(s, 15);

  }

}

void setup() {
  WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector

  Serial.begin(115200);
  //Serial.setDebugOutput(true);
  Serial.println();

  init_cam(); // initialize camera
  mtmn_config = app_mtmn_config();
  aligned_face = dl_matrix3du_alloc(1, FACE_WIDTH, FACE_HEIGHT, 3);
  
  face_id_name_init(&st_face_list, FACE_ID_SAVE_NUMBER, ENROLL_CONFIRM_TIMES);
   //read_face_id_from_flash_with_name(&st_face_list);// Read current face data from on-board flash

  // set sd card
  if(!SD_MMC.begin()){
    Serial.println("Card Mount Failed");
    return;
  }

  // read file from sd card
  File myFile = SD_MMC.open("/facesfile", FILE_WRITE);
  myFile.read((byte *)&st_face_list, sizeof(st_face_list));
  myFile.close();

  // print datas
  Serial.println("print saved faces from sd card");
  face_id_node *head = st_face_list.head;
  for (int i = 0; i < st_face_list.count; i++){
    Serial.printf("stored face name : %s", head->id_name);
    head = head->next;
  }
}

void loop(){
  camera_fb_t * fb=NULL;
  dl_matrix3du_t *image_matrix = NULL;

  fb = esp_camera_fb_get(); // capture image from camera
  // alloc image matrix for face detection & recognition
  image_matrix = dl_matrix3du_alloc(1, fb->width, fb->height, 3);

  // put captured image to image_matrix
  if(!fmt2rgb888(fb->buf, fb->len, fb->format, image_matrix->item)){
    Serial.println("fmt2rgb888 failed");
  }
  // run face detection
  box_array_t *fboxes = face_detect(image_matrix, &mtmn_config);

  if(fboxes) { // face detected
    Serial.println("face detected");
    dl_matrix3d_t *new_id = NULL;

    // if face is correctly aligned
    if (align_face(fboxes, image_matrix, aligned_face) == ESP_OK) {

      new_id = get_face_id(aligned_face); // get face vectors

      if(enrolling) { // current mode is enrolling

        if(nb_enroll < ENROLL_CONFIRM_TIMES){ // not enrolled enough yet
          Serial.println("enrolling ..");
          enroll_face_id_to_flash_with_name(&st_face_list, new_id, new_name);
          nb_enroll++;
        } else {
          nb_enroll = 0;
          enrolling = false;

          // write faces_list to sd card
          Serial.println("writing face_id_name_list to sd card");
          File myFile = SD_MMC.open("/facesfile", FILE_WRITE);
          myFile.write((byte *)&st_face_list, sizeof(st_face_list));
          myFile.close();

        }
      } else { // we are not currently enrolling a new face
        face_id_node *f = recognize_face_with_name(&st_face_list, new_id);
        if (f) {
          Serial.print("Match Face : ");
          Serial.println(f->id_name);
        } else {
          Serial.println("No Match Found ! New face to enroll");
          // generate a new name
          new_name[0] = '\0';
          for (int i = 0; i < length; i++){
            new_name[i] = '0' + random(10);
          }
          new_name[length] = '\0'; // add the null terminator
          Serial.printf("  new name : %s\n", new_name);
          enrolling = true; // trigger enrolling
          nb_enroll = 0;
        }

      } // end of [if(enrolling)]

    } // end of [if(aligned_face)]
    dl_matrix3d_free(new_id);

  } // end of [if(fboxes)]



  dl_matrix3du_free(image_matrix);
  esp_camera_fb_return(fb);
}  // end of loop

These two codes record and read the matrices of faces on the SD CARD. At least they should.

void read_face_id_list_sdcard(face_id_list *l, const char *path) {
  File file = SD_MMC.open(path,FILE_READ);
  l->head =   file.read();
  l->tail =   file.read();
  l->count =  file.read();
  l->size =   file.read();
  l->confirm_times = file.read();
  dl_matrix3d_t **list = l->id_list;
  const int block_len = FACE_ID_SIZE * sizeof(float);
  for(uint8_t i =0;i<l->count;i++)
  {
    list[i] = dl_matrix3d_alloc(1, 1, 1, FACE_ID_SIZE);
    file.read((uint8_t*)list[i]->item,block_len);
  }
  file.close();
}

void write_face_id_list_sdcard(face_id_list *l, const char* path) {
  File file = SD_MMC.open(path,FILE_WRITE);
  file.write(l->head);
  file.write(l->tail);
  file.write(l->count);
  file.write(l->size);
  file.write(l->confirm_times);
  const int block_len = FACE_ID_SIZE * sizeof(float);
  for(uint8_t i =0;i<l->count;i++) {
    file.write((uint8_t*)l->id_list[i]->item,block_len);
  }
  file.close();
}

Could someone join the codes so that it would be possible to save and then compare the read faces with the matrices saved in the SD CARD ?

The attempts I made generate compilation errors because I don't have the necessary knowledge yet. I'm trying to learn from codes that actually work.

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.