上篇文章,测试了EASY EAI Nano的人脸检测功能,本篇进行人脸识别功能。
人脸检测,只是将图像中的人脸的位置检测出来,人脸识别,又增加了一部,在检测到人脸后,还要识别出这张脸是谁的脸。
本篇参考官方文档:https://www.easy-eai.com/document_details/3/110
1 API介绍
组件 |
头文件以及库路径 |
描述 |
系统操作组件 |
easyeai-api/common_api/system_opt |
提供线程操作函数 |
摄像头组件 |
easyeai-api/peripheral_api/camera |
提供摄像头操作函数 |
显示屏组件 |
easyeai-api/peripheral_api/display |
提供显示屏操作函数 |
平面几何组件 |
easyeai-api/algorithm_api/geometry |
提供简单几何运算函数 |
人脸检测组件 |
easyeai-api/algorithm_api/face_detect |
提供人脸检测操作函数 |
人脸校正组件 |
easyeai-api/algorithm_api/face_alignment |
提供人脸校正操作函数 |
人脸识别组件 |
easyeai-api/algorithm_api/face_recognition |
提供人脸识别操作函数 |
主要来看下人脸识别组件。
face_recognition.h的主要内容
int face_recognition_init(rknn_context *ctx, const char * path);
int face_recognition_run(rknn_context ctx, cv::Mat *face_image, float (*feature)[512]);
float face_recognition_comparison(float *feature_1, float *feature_2, int output_len);
int face_recognition_release(rknn_context ctx);
一些参数:
- ctx:输入参数,rknn_context句柄
- path:输入参数,算法模型路径
- face_image:输入参数,图像数据输入(cv::Mat是Opencv的类型)
- feature:输出参数,算法输出的人脸特征码
face_alignment.h的主要内容
cv::Mat face_alignment(cv::Mat img, cv::Point2f* points);
geometry.h的主要内容
typedef struct{
float x;
float y;
}fPoint_t;
typedef struct{
float left;
float top;
float right;
float bottom;
}fRect_t;
typedef struct{
int32_t x;
int32_t y;
}s32Point_t;
typedef struct{
int32_t left;
int32_t top;
int32_t right;
int32_t bottom;
}s32Rect_t;
extern bool point_in_rect(s32Point_t point, s32Rect_t rect);
extern int32_t calc_rect_square(s32Rect_t rect);
extern s32Rect_t min_rect(s32Rect_t rect1, s32Rect_t rect2);
extern s32Rect_t max_rect(s32Rect_t rect1, s32Rect_t rect2);
extern bool rect_is_intersect(s32Rect_t rect1, s32Rect_t rect2);
extern int32_t calc_rect_intersect_square(s32Rect_t rect1, s32Rect_t rect2);
extern double calc_intersect_of_min_rect(s32Rect_t rect1, s32Rect_t rect2);
extern double calc_intersect_of_union(s32Rect_t rect1, s32Rect_t rect2);
2 代码分析与修改
主要的修改是将红外摄像头采集和活体检测去掉,改用外接RGB摄像头,另外,识别结果的显示,将更多的信息(识别的id,人物名称,耗时等)展示在屏幕上。
2.1 图像采集与显示线程(主线程)
重新定义识别结果:
typedef struct{
bool bHasFace;
bool bMatch;
char idStr[128];
char nameStr[128];
float similarity;
uint64_t useTime;
uint32_t x1;
uint32_t y1;
uint32_t x2;
uint32_t y2;
}Result_t;
官方例程用到了红外摄像头,用于活体检测,此次测试,为了使用电脑屏幕上的人物图片进行人脸检测,去掉了活体检测功能,并换做只使用USB摄像头采集RGB图像进行人脸识别。
主函数逻辑如下,和上篇进行人脸检测的代码逻辑类似。
#define COLOR_RED Scalar(255, 0, 0)
#define COLOR_GREEN Scalar(0, 255, 0)
int main(int argc, char **argv)
{
int ret = 0;
int rgbRet = 0;
disp_screen_t screen = {0};
char *pRGBbuf = NULL;
int skip = 0;
pthread_t mTid;
Result_t *pResult = NULL;
Mat image;
ret = usbcamera_init(USB2_0, USB_DIRECT, CAMERA_WIDTH, CAMERA_HEIGHT, 180);
if (ret) {
printf("error: %s, %d\n", __func__, __LINE__);
goto exit_donothing;
}
pRGBbuf = NULL;
pRGBbuf = (char *)malloc(IMAGE_SIZE);
if (!pRGBbuf) {
printf("error: %s, %d\n", __func__, __LINE__);
ret = -1;
goto exit_freeusb;
}
skip = 10;
while(skip--) {
ret = usbcamera_getframe(USB2_0, USB_DIRECT, pRGBbuf);
if (ret) {
printf("error: %s, %d\n", __func__, __LINE__);
goto exit_freeusb_freebuf;
}
}
pthread_mutex_init(&img_lock, NULL);
pResult = (Result_t *)malloc(sizeof(Result_t));
if(NULL == pResult){
goto exit_free_all;
}
memset(pResult, 0, sizeof(Result_t));
if(0 != CreateNormalThread(detect_thread_entry, pResult, &mTid)){
free(pResult);
}
screen.screen_width = SCREEN_WIDTH;
screen.screen_height = SCREEN_HEIGHT;
screen.wins[0].enable = 1;
screen.wins[0].in_fmt = IMAGE_TYPE_RGB888;
screen.wins[0].in_w = CAMERA_WIDTH;
screen.wins[0].in_h = CAMERA_HEIGHT;
screen.wins[0].rotation = 90;
screen.wins[0].win_x = 0;
screen.wins[0].win_y = 0;
screen.wins[0].win_w = 720;
screen.wins[0].win_h = 1280;
ret = disp_init_pro(&screen);
if (ret) {
printf("error: %s, %d\n", __func__, __LINE__);
goto exit_free_all;
}
while(1)
{
pthread_mutex_lock(&img_lock);
ret = usbcamera_getframe(USB2_0, USB_DIRECT, pRGBbuf);
if (0 != rgbRet)
{
printf("error: %s, %d\n", __func__, __LINE__);
pthread_mutex_unlock(&img_lock);
continue;
}
algorithm_image = Mat(CAMERA_HEIGHT, CAMERA_WIDTH, CV_8UC3, pRGBbuf);
image = algorithm_image.clone();
pthread_mutex_unlock(&img_lock);
if (pResult->bHasFace)
{
Scalar color;
if(pResult->bMatch)
{
color = COLOR_GREEN;
cv::putText(image, std::string("idStr: ") + std::string(pResult->idStr), cv::Point2f(30, 50), cv::FONT_HERSHEY_SIMPLEX, 1.45, CV_RGB(255,0,0),3.0);
cv::putText(image, std::string("name: ") + std::string(pResult->nameStr), cv::Point2f(30, 100), cv::FONT_HERSHEY_SIMPLEX, 1.45, CV_RGB(255,0,0),3.0);
cv::putText(image, std::string("similarity: ") + std::to_string(pResult->similarity), cv::Point2f(30, 150), cv::FONT_HERSHEY_SIMPLEX, 1.45, CV_RGB(255,0,0),3.0);
cv::putText(image, std::string("use time: ") + std::to_string(pResult->useTime), cv::Point2f(30, 200), cv::FONT_HERSHEY_SIMPLEX, 1.45, CV_RGB(255,0,0),3.0);
}
else
{
color = COLOR_RED;
cv::putText(image, std::string("unknow face"), cv::Point2f(30, 50), cv::FONT_HERSHEY_SIMPLEX, 1.45, CV_RGB(0,0,255),3.0);
}
rectangle(image, Point(pResult->x1, pResult->y1), Point(pResult->x2, pResult->y2), color, 3);
}
disp_commit(image.data, IMAGE_SIZE);
usleep(20*1000);
}
exit_free_all:
pthread_mutex_destroy(&img_lock);
exit_freeusb_freebuf:
free(pRGBbuf);
pRGBbuf = NULL;
exit_freeusb:
usbcamera_exit(USB2_0, USB_DIRECT);
exit_donothing:
return ret;
}
2.2 人脸识别处理
去掉红外摄像头的活体检测逻辑,只使用USB摄像头的图像进行人脸识别
void *detect_thread_entry(void *para)
{
int ret;
uint64_t start_time,end_time;
Result_t *pResult = (Result_t *)para;
rknn_context detect_ctx;
std::vector<det> detect_result;
Point2f points[5];
s32Rect_t rgbRect;
printf("face detect init!\n");
ret = face_detect_init(&detect_ctx, "./face_detect.model");
if( ret < 0)
{
printf("face_detect fail! ret=%d\n", ret);
return NULL;
}
rknn_context recognition_ctx;
float face_feature[512];
printf("face recognition init!\n");
ret = face_recognition_init(&recognition_ctx, "./face_recognition.model");
if( ret < 0)
{
printf("face_recognition fail! ret=%d\n", ret);
return NULL;
}
database_init();
faceData_t *pFaceData = (faceData_t *)malloc(MAX_USER_NUM * sizeof(faceData_t));
memset(pFaceData, 0, MAX_USER_NUM * sizeof(faceData_t));
int peopleNum = database_getData_to_memory(pFaceData);
keyEvent_init();
set_event_handle(dataBase_opt_handle);
Mat image;
Mat face_algin;
float similarity;
int face_index = 0;
while(1)
{
if(g_delete_all_record)
{
g_delete_all_record = false;
database_delete_all_record();
peopleNum = database_getData_to_memory(pFaceData);
}
if(algorithm_image.empty())
{
usleep(5);
continue;
}
pthread_mutex_lock(&img_lock);
image = algorithm_image.clone();
pthread_mutex_unlock(&img_lock);
ret = face_detect_run(detect_ctx, image, detect_result);
if(ret <= 0)
{
memset(pResult, 0 , sizeof(Result_t));
g_input_feature = false;
usleep(1000);
continue;
}
rgbRect.left = (uint32_t)(detect_result[0].box.x);
rgbRect.top = (uint32_t)(detect_result[0].box.y);
rgbRect.right = (uint32_t)(detect_result[0].box.x + detect_result[0].box.width);
rgbRect.bottom = (uint32_t)(detect_result[0].box.y + detect_result[0].box.height);
pResult->bHasFace = true;
pResult->x1 = rgbRect.left;
pResult->y1 = rgbRect.top;
pResult->x2 = rgbRect.right;
pResult->y2 = rgbRect.bottom;
for (int i = 0; i < (int)detect_result[0].landmarks.size(); ++i) {
points[i].x = (int)detect_result[0].landmarks[i].x;
points[i].y = (int)detect_result[0].landmarks[i].y;
}
face_algin = face_alignment(image, points);
start_time = get_timeval_ms();
face_recognition_run(recognition_ctx, &face_algin, &face_feature);
end_time = get_timeval_ms();
pResult->useTime = end_time - start_time;
printf("\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
printf("face_recognition_run use time: %llu\n", pResult->useTime);
similarity = -0.5;
if(peopleNum > 0)
{
for(face_index = 0; face_index < peopleNum; ++face_index)
{
similarity = face_recognition_comparison(face_feature, (float *)((pFaceData + face_index)->feature), 512);
if(similarity > 0.5)
{
break;
}
}
}
pResult->similarity = similarity;
printf("similarity:%f\n", similarity);
if((face_index < peopleNum)&&(similarity > 0.5))
{
pResult->bMatch = true;
memcpy(pResult->idStr, (pFaceData + face_index)->id, 128);
printf("idStr : %s\n", pResult->idStr);
database_id_is_exist(pResult->idStr, pResult->nameStr, sizeof(pResult->nameStr));
printf("person name : %s\n", pResult->nameStr);
if(g_input_feature)
{
g_input_feature = false;
database_add_record(pResult->idStr, pResult->nameStr, (char *)face_feature, sizeof(face_feature));
peopleNum = database_getData_to_memory(pFaceData);
}
}
else
{
pResult->bMatch = false;
if(g_input_feature)
{
g_input_feature = false;
char idStr[32]={0};
char nameStr[32]={0};
sprintf(idStr, "%05d", face_index+1);
sprintf(nameStr, "people_%d", face_index+1);
database_add_record(idStr, nameStr, (char *)face_feature, sizeof(face_feature));
peopleNum = database_getData_to_memory(pFaceData);
}
}
usleep(16*1000);
}
free(pFaceData);
database_exit();
face_recognition_release(recognition_ctx);
face_detect_release(detect_ctx);
return NULL;
}
3 测试
测试视频见文章底部视频,这里再放一张测试图片:
4 总结
本篇介绍了EASY EAI Nano的人脸识别功能,与上篇的人脸检测相比,在检测到有人脸的基础上,通过先录入人脸显示到数据库,可以对比当前识别的谁的脸,实际测试,去掉活体检测功能后,通过外接USB摄像头来识别电脑屏幕上的3个人的多张不同人脸,可以分辨出不同人的人脸。