240 lines
7.3 KiB
C++
240 lines
7.3 KiB
C++
|
#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);
|
||
|
}
|