谷动谷力

 找回密码
 立即注册
查看: 2740|回复: 0
收起左侧

基于 NXP i.MX 的人脸识别初探

[复制链接]
发表于 2022-5-5 22:26:28 | 显示全部楼层 |阅读模式
基于 NXP i.MX 的人脸识别初探

一、 人脸识别的facenet 模型

1.1、facenet
谷歌人脸检测算法,发表于 CVPR 2015,利用相同人脸在不同角度等姿态的照片下有高内聚性,不同人脸有低耦合性,提出使用 cnn + triplet mining 方法,在 LFW 数据集上准确度达到 99.63%。

通过 CNN 将人脸映射到欧式空间的特征向量上,实质上:不同图片人脸特征的距离较大;通过相同个体的人脸的距离,总是小于不同个体的人脸这一先验知识训练网络。测试时只需要计算人脸特征EMBEDDING,然后计算距离使用阈值即可判定两张人脸照片是否属于相同的个体。

1.png
图1:人脸识别过程

简单来讲,在使用阶段,facenet即是:
1、输入一张人脸图片
2、通过深度学习网络提取特征
3、L2标准化
4、得到128维特征向量。

其中 Inception-ResNetV1是facenet使用的主干网络,如下图所示:


2.png

图2:Inception-ResNetV1 网络结构

可以看到里面的结构分为几个重要的部分
1、stem
2、Inception-resnet-A
3、Inception-resnet-B
4、Inception-resnet-C
为了能够在手机或者是其他端平台实时运行人脸识别功能,需要对其中的 Backbone 进行替换成更更小同事精度也高的模型,于是又提出了 MobileFaceNet 模型。



1.2、MobileFaceNetMobileFaceNets,该模型使用少于一百万个参数,专门针对移动和嵌入式设备上的高精度实时人脸验证而量身定制。文章首先分析普通的mobilenet应用在人脸验证上有哪些缺陷,本文设计的MobileFaceNet可以很好克服这个缺陷,在同样的实验条件下,MobileFaceNet达到明显优越的精度,而且实际速度是MobileNetV2的两倍。单个4M尺寸大小的MobileFaceNet在MS-Celeb-1M数据集上用ArcFace训练后,可以在LFW达到99.55%精度,甚至可以和一些大型几百M的CNN网络相比较。最快的MobileFaceNet在手机上推断时间仅有18毫秒,对于人脸验证,相比之前的MobileCNN,它的效率大大提高。



二、i.MX 中人脸识别


2.1、数据库的初始化数据库中每一张图片对应一个人的人脸,图片名字就是这个人的名字。数据库初始化指的是人脸数据库的初始化。想要实现人脸识别,首先要知道自己需要识别哪些人脸。所以我们数据库的一个功能,将想要检测到的人脸放入数据库中,并进行编码。
数据库的初始化具体执行的过程就是:


1、遍历数据库中所有的图片。
2、检测每个图片中的人脸位置。

该步需要使用到face_detect_helpers.cpp 中的 init_face_detect() 函数功能:
  1. void init_face_detect(Settings *setting)
  2. {
  3.   String face_cascade_name = "haarcascade_frontalface_alt.xml";
  4.   if( !face_cascade.load(face_cascade_name) )
  5.     printf("--(!)Error loading haarcascade_frontalface_alt.xml\n");
  6.   s = setting;
  7. }
复制代码


3、利用CascadeClassifier将人脸截取下载。

在face_recognition.cpp 中可以实现:
  1.     Mat face = get_data_face(img);
复制代码

其中 get_data_face() 中用来检测获取人脸 face ,所使用的的模型是 haarcascade_frontalface_alt.xml
  1. <div>Mat get_data_face(Mat &img)
  2. </div>{
  3.   float scale = (float)rescaled_width / img.cols;
  4.   if (scale > 1)
  5.     scale = 1;
  6.   Mat small_img = preprocess(img, scale);
  7.   Rect faceRef = detect_face(small_img, scale);
  8.   Mat face;
  9.   if (!faceRef.empty())
  10.   {
  11.     cvtColor(img(faceRef), face, COLOR_BGR2RGB);
  12.   }
  13.   return face;
  14. }
复制代码


5、利用facenet将人脸进行编码。

6、将所有人脸编码的结果放在一个array中。

利用 facenet 模型将 face 信息转为 feature_vec ,并存在 array 中
  1. std::array<float, num_class> feature_vec = get_output_tensor(face, s);
复制代码

第6步得到的列表就是已知的所有人脸的特征列表,在之后获得的实时图片中的人脸都需要与已知人脸进行比对,这样我们才能知道谁是谁。

其完整的实现代码如下:
face_recognition.cpp


  1. void init_database(Settings *s)
  2. {
  3.   if (s->verbose)
  4.     LOG(INFO) << "Enrolling...." << "\r\n";
  5.   std::vector image_names;
  6.   const int dir_err = mkdir(s->data_dir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
  7.   if (dir_err != -1 && errno != EEXIST)
  8.   {
  9.     return;
  10.   }
  11.   glob(s->data_dir, image_names);

  12.   auto start_time = GET_TIME_IN_US();
  13.   for (size_t i = 0; i < image_names.size(); i++)
  14.   {
  15.     if (s->verbose)
  16.       LOG(INFO) << "Add face " << i + 1 << "\r\n";
  17.     Mat img = imread(image_names, IMREAD_COLOR);
  18.     Mat face = get_data_face(img);
  19.     if (face.empty())
  20.     {
  21.       continue;
  22.     }
  23.     std::array<float, num_class> feature_vec = get_output_tensor(face, s);
  24.     cvtColor(face, face, COLOR_RGB2BGR);
  25.     std::string label = image_names;
  26.     label.erase(0, s->data_dir.length());
  27.     label.erase(label.find("."));
  28.     face_database[label] = {face, feature_vec};
  29.   }
  30.   auto stop_time = GET_TIME_IN_US();
  31.   if (s->profiling)
  32.   {
  33.     LOG(INFO) << "init face database\n\r";
  34.     LOG(INFO) << "total time: "
  35.               << (GET_TIME_DIFF(start_time, stop_time)) / 1000
  36.               << " ms \n\r";
  37.     LOG(INFO) << "average time: "
  38.               << (GET_TIME_DIFF(start_time, stop_time)) / 1000 / image_names.size()
  39.               << " ms \n\r";
  40.   }
  41.   if (s->verbose)
  42.     LOG(INFO) << "The all " << image_names.size() << "faces database is done!\r\n";
  43. }
复制代码




2.2、实时图像的处理
    在上面讲完数据库的初始化部分后,既可以对摄像头实时处理图像数据部分开始进行研究,了解 i.MX 中图像处理流程。

2.2.1、人脸的检测    首先是从摄像头抓取 camera 图像,图像尺寸大小为 640 x 480


  1. void init_camera()
  2. {
  3.   cap.open(s->camera);
  4.   if (!cap.isOpened())
  5.   {
  6.     LOG(FATAL) << "Capture from camera #" << s->camera << " didn't work"
  7.                << "\n\r";
  8.     exit(-1);
  9.   }
  10.   cap.set(CAP_PROP_FRAME_WIDTH, 640);
  11.   cap.set(CAP_PROP_FRAME_HEIGHT, 480);
  12. }
复制代码



利用 opencv 中的 CascadeClassifier face_cascade ,人脸检测器来检测人脸,过程如下:

  1. Rect detect_face(Mat &img, float scale)
  2. {
  3.   std::vector faces;
  4.   face_cascade.detectMultiScale(img, faces, 1.3, 3,
  5.                                 CASCADE_FIND_BIGGEST_OBJECT, Size(65, 65));
  6.   Rect faceRef;
  7.   if (faces.empty())
  8.   {
  9.     return faceRef;
  10.   }
  11.   for (int i = 0; i < faces.size(); i++)
  12.   {
  13.     if (faces.area() > faceRef.area())
  14.     {
  15.       faceRef = faces;
  16.     }
  17.   }
  18.   faceRef = Rect(Point(cvRound(faceRef.x / scale),
  19.                        cvRound(faceRef.y / scale)),
  20.                  Point(cvRound((faceRef.x + faceRef.width - 1) / scale),
  21.                        cvRound((faceRef.y + faceRef.height - 1) / scale)));
  22.   return faceRef;
  23. }
复制代码

将人脸 face 从输入的图像中截取下来,节省计算资源:

  1. Mat get_data_face(Mat &img)
  2. {
  3.   float scale = (float)rescaled_width / img.cols;
  4.   if (scale > 1)
  5.     scale = 1;
  6.   Mat small_img = preprocess(img, scale);
  7.   Rect faceRef = detect_face(small_img, scale);
  8.   Mat face;
  9.   if (!faceRef.empty())
  10.   {
  11.     cvtColor(img(faceRef), face, COLOR_BGR2RGB);
  12.   }
  13.   return face;
  14. }
复制代码



2.2.2、Tflite 中对人脸进行编码
i.MX 中对人脸进行编码,源码中并没有将 inference 过程给出,仅仅是针对不同的模型进行推理,代码如下所示:


  1. std::array<float, num_class> get_output_tensor(Mat img, Settings *s)
  2. {

  3.   int output = interpreter->outputs()[0];
  4.   TfLiteTensor *output_tensor = interpreter->tensor(output);
  5.   TfLiteIntArray *output_dims = output_tensor->dims;
  6.   // assume output dims to be something like (1, 1, ... ,size)
  7.   auto output_size = output_dims->data[output_dims->size - 1];
  8.   std::array<float, num_class> array;
  9.   switch (interpreter->tensor(output)->type)
  10.   {
  11.   case kTfLiteFloat32:
  12.   {
  13.     float *output_float = interpreter->typed_output_tensor(0);
  14.     for (int i = 0; i < output_size; i++)
  15.       array = output_float;
  16.     break;
  17.   }
  18.   case kTfLiteUInt8:
  19.   {
  20.     uint8_t *output_uint8 = interpreter->typed_output_tensor(0);
  21.     for (int i = 0; i < output_size; i++)
  22.       array = output_uint8;
  23.     break;
  24.   }
  25.   default:
  26.   {
  27.     LOG(FATAL) << "cannot handle output type "
  28.                << interpreter->tensor(input)->type << " yet";
  29.     exit(-1);
  30.   }
  31.   }
  32.   return array;
  33. }
复制代码



2.2.3、将实时图像中的人脸特征与数据库中的进行对比

    对得到的人脸特征编码进行计算,大于 threshold 则判断是同一人脸,具体计算过程如下:


  1. std::pair<std::string, float> predict_label(std::array<float, num_class> &pred, float threshold)
  2. {
  3.   float ret = 0, mod1 = 0, mod2 = 0;
  4.   float max = 0;
  5.   std::string label;
  6.   for (int i = 0; i < num_class; i++)
  7.     mod1 += pred * pred;
  8.   for (auto &face : face_database)
  9.   {
  10.     ret = 0, mod2 = 0;
  11.     std::array<float, num_class> &vec = face.second.second;
  12.     for (int i = 0; i < num_class; i++)
  13.     {
  14.       ret += pred * vec;
  15.       mod2 += vec * vec;
  16.     }
  17.     float cosine_similarity = (ret / sqrt(mod1) / sqrt(mod2) + 1) / 2.0;
  18.     if (max <= cosine_similarity)
  19.     {
  20.       max = cosine_similarity;
  21.       label = face.first;
  22.     }
  23.   }
  24.   if (max < threshold)
  25.   {
  26.     label.clear();
  27.   }
  28.   return {label, max};
  29. }
复制代码

三、总结归纳

        通过本文的讲述,初步阐述了如何在NXP 的 i.MX 中使用 tflite 框架对人脸进行识别的过程,重点强调算法实现的过程原理。当然实际上的操作还有增加人脸数据库的内容,需要再官网的demo 中演示查看效果。


四、参考资料

1.《睿智的目标检测40——Keras搭建Retinaface人脸检测与关键点定位平台》:

        https://blog.csdn.net/weixin_44791964/article/details/106871010



回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|深圳市光明谷科技有限公司|光明谷商城|Sunshine Silicon Corpporation ( 粤ICP备14060730号|Sitemap

GMT+8, 2022-9-27 11:44 , Processed in 0.152774 second(s), 34 queries .

Powered by Discuz! X3.2 Licensed

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表