✨ feature: face recognition
parent
83b414dd0d
commit
ecd5785d02
|
@ -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<dl::detect::result_t> &detect_candidates = detector.infer((uint16_t *)frame->buf, {(int)frame->height, (int)frame->width, 3});
|
||||
std::list<dl::detect::result_t> &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);
|
||||
}
|
|
@ -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);
|
Loading…
Reference in New Issue