From ecd5785d02dd94a1fe5ce84086efe8feb561903c Mon Sep 17 00:00:00 2001 From: yuanjiong Date: Wed, 20 Oct 2021 20:15:03 +0800 Subject: [PATCH] :sparkles: feature: face recognition --- .../modules/ai/who_human_face_recognition.cpp | 239 ++++++++++++++++++ .../modules/ai/who_human_face_recognition.hpp | 21 ++ 2 files changed, 260 insertions(+) create mode 100644 components/modules/ai/who_human_face_recognition.cpp create mode 100644 components/modules/ai/who_human_face_recognition.hpp diff --git a/components/modules/ai/who_human_face_recognition.cpp b/components/modules/ai/who_human_face_recognition.cpp new file mode 100644 index 0000000..c416e73 --- /dev/null +++ b/components/modules/ai/who_human_face_recognition.cpp @@ -0,0 +1,239 @@ +#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_detection"; + +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; + + 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); + 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: + recognizer->delete_id(); + 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()) + { + 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); +} diff --git a/components/modules/ai/who_human_face_recognition.hpp b/components/modules/ai/who_human_face_recognition.hpp new file mode 100644 index 0000000..b7841d8 --- /dev/null +++ b/components/modules/ai/who_human_face_recognition.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "freertos/FreeRTOS.h" +#include "freertos/queue.h" +#include "freertos/task.h" +#include "freertos/semphr.h" + +typedef enum +{ + IDLE = 0, + DETECT, + ENROLL, + RECOGNIZE, + DELETE, +} recognizer_state_t; + +void register_human_face_recognition(QueueHandle_t frame_i, + QueueHandle_t event, + QueueHandle_t result, + QueueHandle_t frame_o = NULL, + const bool camera_fb_return = false);