AI挑战营(进阶):6. 多人人脸识别+rtsp
本帖最后由 waterman 于 2024-12-4 09:35 编辑基于 https://github.com/LuckfoxTECH/luckfox_pico_rkmpi_example.git 以luckfox_pico_rtsp_retinaface为例,进行修改
# 新建工程
新复制一份改名为
```
luckfox_pico_rtsp_retinafacenet
```
并在build.sh中添加
重新编译生成luckfox_pico_rtsp_retinafacenet_demo,上传至板卡测试可以正常运行:
# 工程修改
经过对比,retinaface.h为retinaface_facenet.h的子集,因此直接对其进行替换。
经测试可以直接替换并正常使用。工程目录如下:
仿照luckfox_pico_retinaface_facenet对工程进行了修改,添加了facenet于luckfox_pico_rtsp_retinafacenet_one_shot,实现了单个人脸的录入与识别。并于luckfox_pico_rtsp_retinafacenet_three_face中实现了一个及三个人脸的录入与识别。
具体思路为在while(1)大循环中,每次获取一帧摄像头采集到的图像数据,输入到retinaface中,得到n个检测到的人脸,分别对每个人脸进行识别并标注信息,最后将其进行推流。
关键代码如下:
1. 模型加载
```python
// Rknn model
rknn_app_context_t app_retinaface_ctx;
rknn_app_context_t app_facenet_ctx;
object_detect_result_list od_results;
const char *retinaface_model_path = "./model/retinaface.rknn";
const char *facenet_model_path = "./model/mobilefacenet.rknn";
memset(&app_retinaface_ctx, 0, sizeof(rknn_app_context_t));
memset(&app_facenet_ctx, 0, sizeof(rknn_app_context_t));
//Init Model
if(init_retinaface_facenet_model(retinaface_model_path, facenet_model_path, &app_retinaface_ctx, &app_facenet_ctx) != RK_SUCCESS)
{
RK_LOGE("rknn model init fail!");
return -1;
}
```
2. 录入三个参考人脸
```python
//Init Opencv-mobile
int ret;
cv::Mat retinaface_input(retinaface_height, retinaface_width, CV_8UC3, app_retinaface_ctx.input_mems->virt_addr);
cv::Mat facenet_input(facenet_height, facenet_width, CV_8UC3, app_facenet_ctx.input_mems->virt_addr);
//Get referencve img feature
const char *image1_path = "./model/test1.png";
const char *image2_path = "./model/test2.png";
const char *image3_path = "./model/test3.png";
//get image 1 feature
cv::Mat image = cv::imread(image1_path);
letterbox(image,facenet_input);//resize image to 160x160
ret = rknn_run(app_facenet_ctx.rknn_ctx, nullptr);
if (ret < 0) {
printf("rknn_run fail! ret=%d\n", ret);
return -1;
}
uint8_t*output = (uint8_t *)(app_facenet_ctx.output_mems->virt_addr);
float* reference1_out_fp32 = (float*)malloc(sizeof(float) * 128);
output_normalization(&app_facenet_ctx,output,reference1_out_fp32);
//get image 2 feature
image = cv::imread(image2_path);
letterbox(image,facenet_input);//resize image to 160x160
ret = rknn_run(app_facenet_ctx.rknn_ctx, nullptr);
if (ret < 0) {
printf("rknn_run fail! ret=%d\n", ret);
return -1;
}
output = (uint8_t *)(app_facenet_ctx.output_mems->virt_addr);
float* reference2_out_fp32 = (float*)malloc(sizeof(float) * 128);
output_normalization(&app_facenet_ctx,output,reference2_out_fp32);
//get image 3 feature
image = cv::imread(image3_path);
letterbox(image,facenet_input);//resize image to 160x160
ret = rknn_run(app_facenet_ctx.rknn_ctx, nullptr);
if (ret < 0) {
printf("rknn_run fail! ret=%d\n", ret);
return -1;
}
output = (uint8_t *)(app_facenet_ctx.output_mems->virt_addr);
float* reference3_out_fp32 = (float*)malloc(sizeof(float) * 128);
output_normalization(&app_facenet_ctx,output,reference3_out_fp32);
```
3. 人脸检测与识别
```
cv::resize(bgr, retinaface_input, cv::Size(retinaface_width ,retinaface_height), 0, 0, cv::INTER_LINEAR);
// memcpy(app_retinaface_ctx.input_mems->virt_addr, model_bgr.data, retinaface_width * retinaface_height * 3);
inference_retinaface_model(&app_retinaface_ctx, &od_results);
for(int i = 0; i < od_results.count; i++)
{
//Get det
object_detect_result *det_result = &(od_results.results);
sX = (int)((float)det_result->box.left *scale_x);
sY = (int)((float)det_result->box.top *scale_y);
eX = (int)((float)det_result->box.right*scale_x);
eY = (int)((float)det_result->box.bottom *scale_y);
// printf("%d %d %d %d\n",sX,sY,eX,eY);
cv::rectangle(frame,cv::Point(sX,sY),cv::Point(eX,eY),cv::Scalar(0,255,0),3);
//Face capture
cv::Rect roi(sX,sY,
(eX - sX),
(eY- sY));
cv::Mat face_img = frame(roi);
letterbox(face_img,facenet_input);
//rknn run
ret = rknn_run(app_facenet_ctx.rknn_ctx, nullptr);
if (ret < 0) {
printf("rknn_run fail! ret=%d\n", ret);
return -1;
}
output = (uint8_t *)(app_facenet_ctx.output_mems->virt_addr);
output_normalization(&app_facenet_ctx, output, out_fp32);
float norm1 = get_duclidean_distance(reference1_out_fp32,out_fp32);
float norm2 = get_duclidean_distance(reference2_out_fp32,out_fp32);
float norm3 = get_duclidean_distance(reference3_out_fp32,out_fp32);
float min_norm;
int min_index;
printf("@ (%d %d %d %d) %.3f %.3f %.3f\n",sX,sY,eX,eY,norm1,norm2,norm3);
if(norm1 < norm2 && norm1 < norm3)
{
min_norm = norm1;
min_index = 1;
}
else if(norm2 < norm1 && norm2 < norm3)
{
min_norm = norm2;
min_index = 2;
}
else
{
min_norm = norm3;
min_index = 3;
}
//Draw text
if(min_norm < 1.1)
{
sprintf(show_text, "face%d,norm=%.3f", min_index, min_norm);
}
else
{
sprintf(show_text, "unknow");
}
cv::putText(frame, show_text, cv::Point(sX, sY - 8),
cv::FONT_HERSHEY_SIMPLEX,0.5,
cv::Scalar(0,255,0),
1);
}
```
4. 内存及模型释放
```python
// Release rknn model
free(reference1_out_fp32);
free(reference2_out_fp32);
free(reference3_out_fp32);
free(out_fp32);
release_facenet_model(&app_facenet_ctx);
release_retinaface_model(&app_retinaface_ctx);
```
# 效果测试
网上随便找了一张待检测图片如下:
我们录入的三个人脸依次如下:
## 单张人脸识别
## 三张人脸识别
# 演示视频
## 单张人脸
dda1b4aefd9569fac011d0de3986f3b8<br/>
## 多张人脸
c5cb6a993c0e33bc23e419b5abb762e4<br/>
# 结果分析
目前虽然基本实现功能,但是效果还不是特别好。考虑可能会是以下几点原因的影响:
1. 人脸录入需自行截取人脸部分的图片,直接输入facenet,因此检测结果不是很理想。考虑可以在录入的时候加入retinaface,尝试能否提升检测的准确性。
2. 检测的准确性受阈值的影响,可适当调节检测的阈值来提高识别效果。
3. 还有可能是模型量化时量化数据太少的问题。
此外,也可以额外加上fps显示实时帧率。
<p>录入的是三个,为什么检测圈出来的基本上都是4个 </p>
页:
[1]