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.