#include "who_human_face_recognition.hpp" #include "esp_log.h" #include "esp_camera.h" #include "dl_image.hpp" #include "fb_gfx.h" #include "human_face_detect_msr01.hpp" #include "human_face_detect_mnp01.hpp" #include "face_recognition_tool.hpp" #if CONFIG_MFN_V1 #if CONFIG_S8 #include "face_recognition_112_v1_s8.hpp" #elif CONFIG_S16 #include "face_recognition_112_v1_s16.hpp" #endif #endif #include "who_ai_utils.hpp" using namespace std; using namespace dl; static const char *TAG = "human_face_recognition"; static QueueHandle_t xQueueFrameI = NULL; static QueueHandle_t xQueueEvent = NULL; static QueueHandle_t xQueueFrameO = NULL; static QueueHandle_t xQueueResult = NULL; static recognizer_state_t gEvent = DETECT; static bool gReturnFB = true; static face_info_t recognize_result; SemaphoreHandle_t xMutex; typedef enum { SHOW_STATE_IDLE, SHOW_STATE_DELETE, SHOW_STATE_RECOGNIZE, SHOW_STATE_ENROLL, } show_state_t; #define RGB565_MASK_RED 0xF800 #define RGB565_MASK_GREEN 0x07E0 #define RGB565_MASK_BLUE 0x001F #define FRAME_DELAY_NUM 16 static void rgb_print(camera_fb_t *fb, uint32_t color, const char *str) { fb_gfx_print(fb, (fb->width - (strlen(str) * 14)) / 2, 10, color, str); } static int rgb_printf(camera_fb_t *fb, uint32_t color, const char *format, ...) { char loc_buf[64]; char *temp = loc_buf; int len; va_list arg; va_list copy; va_start(arg, format); va_copy(copy, arg); len = vsnprintf(loc_buf, sizeof(loc_buf), format, arg); va_end(copy); if (len >= sizeof(loc_buf)) { temp = (char *)malloc(len + 1); if (temp == NULL) { return 0; } } vsnprintf(temp, len + 1, format, arg); va_end(arg); rgb_print(fb, color, temp); if (len > 64) { free(temp); } return len; } static void task_process_handler(void *arg) { camera_fb_t *frame = NULL; HumanFaceDetectMSR01 detector(0.3F, 0.3F, 10, 0.3F); HumanFaceDetectMNP01 detector2(0.4F, 0.3F, 10); #if CONFIG_MFN_V1 #if CONFIG_S8 FaceRecognition112V1S8 *recognizer = new FaceRecognition112V1S8(); #elif CONFIG_S16 FaceRecognition112V1S16 *recognizer = new FaceRecognition112V1S16(); #endif #endif show_state_t frame_show_state = SHOW_STATE_IDLE; recognizer_state_t _gEvent; recognizer->set_partition(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "fr"); int partition_result = recognizer->set_ids_from_flash(); while (true) { xSemaphoreTake(xMutex, portMAX_DELAY); _gEvent = gEvent; gEvent = DETECT; xSemaphoreGive(xMutex); if (_gEvent) { bool is_detected = false; if (xQueueReceive(xQueueFrameI, &frame, portMAX_DELAY)) { std::list &detect_candidates = detector.infer((uint16_t *)frame->buf, {(int)frame->height, (int)frame->width, 3}); std::list &detect_results = detector2.infer((uint16_t *)frame->buf, {(int)frame->height, (int)frame->width, 3}, detect_candidates); if (detect_results.size() == 1) is_detected = true; if (is_detected) { switch (_gEvent) { case ENROLL: recognizer->enroll_id((uint16_t *)frame->buf, {(int)frame->height, (int)frame->width, 3}, detect_results.front().keypoint, "", true); ESP_LOGW("ENROLL", "ID %d is enrolled", recognizer->get_enrolled_ids().back().id); frame_show_state = SHOW_STATE_ENROLL; break; case RECOGNIZE: recognize_result = recognizer->recognize((uint16_t *)frame->buf, {(int)frame->height, (int)frame->width, 3}, detect_results.front().keypoint); print_detection_result(detect_results); if (recognize_result.id > 0) ESP_LOGI("RECOGNIZE", "Similarity: %f, Match ID: %d", recognize_result.similarity, recognize_result.id); else ESP_LOGE("RECOGNIZE", "Similarity: %f, Match ID: %d", recognize_result.similarity, recognize_result.id); frame_show_state = SHOW_STATE_RECOGNIZE; break; case DELETE: vTaskDelay(10); recognizer->delete_id(true); ESP_LOGE("DELETE", "% d IDs left", recognizer->get_enrolled_id_num()); frame_show_state = SHOW_STATE_DELETE; break; default: break; } } if (frame_show_state != SHOW_STATE_IDLE) { static int frame_count = 0; switch (frame_show_state) { case SHOW_STATE_DELETE: rgb_printf(frame, RGB565_MASK_RED, "%d IDs left", recognizer->get_enrolled_id_num()); break; case SHOW_STATE_RECOGNIZE: if (recognize_result.id > 0) rgb_printf(frame, RGB565_MASK_GREEN, "ID %d", recognize_result.id); else rgb_print(frame, RGB565_MASK_RED, "who ?"); break; case SHOW_STATE_ENROLL: rgb_printf(frame, RGB565_MASK_BLUE, "Enroll: ID %d", recognizer->get_enrolled_ids().back().id); break; default: break; } if (++frame_count > FRAME_DELAY_NUM) { frame_count = 0; frame_show_state = SHOW_STATE_IDLE; } } if (detect_results.size()) { #if !CONFIG_IDF_TARGET_ESP32S3 print_detection_result(detect_results); #endif draw_detection_result((uint16_t *)frame->buf, frame->height, frame->width, detect_results); } } if (xQueueFrameO) { xQueueSend(xQueueFrameO, &frame, portMAX_DELAY); } else if (gReturnFB) { esp_camera_fb_return(frame); } else { free(frame); } if (xQueueResult && is_detected) { xQueueSend(xQueueResult, &recognize_result, portMAX_DELAY); } } } } static void task_event_handler(void *arg) { recognizer_state_t _gEvent; while (true) { xQueueReceive(xQueueEvent, &(_gEvent), portMAX_DELAY); xSemaphoreTake(xMutex, portMAX_DELAY); gEvent = _gEvent; xSemaphoreGive(xMutex); } } void register_human_face_recognition(const QueueHandle_t frame_i, const QueueHandle_t event, const QueueHandle_t result, const QueueHandle_t frame_o, const bool camera_fb_return) { xQueueFrameI = frame_i; xQueueFrameO = frame_o; xQueueEvent = event; xQueueResult = result; gReturnFB = camera_fb_return; xMutex = xSemaphoreCreateMutex(); xTaskCreatePinnedToCore(task_process_handler, TAG, 4 * 1024, NULL, 5, NULL, 0); if (xQueueEvent) xTaskCreatePinnedToCore(task_event_handler, TAG, 4 * 1024, NULL, 5, NULL, 1); }