【前言】
【新提醒】【EASY EAI Orin Nano开发板试用体验】人脸识别体验 - EASY EAI灵眸科技 - 电子技术论坛 - 广受欢迎的专业电子论坛!
在这一篇中,我使用官方示例体验了人脸识别,可以通过两张图片进行对比,来实现人脸的识别功能。这一篇,我将分享如何将提取出来的人脸特征进行保存,一来以提升识别速度,二来为以后的人脸识别数据库打基础。
【功能前期设计】
在官方的教程中,我们从流程图中看到识别的流程是这样的:

如果是刚刚开始,那莫,我们需要对两张不同的图片进行同样的人脸特提取,最后是对人脸特征进行对比。为了提升效率,我们可以在人脸特征提取后,将这个特征值存入文件。在下次拿到图片文件时,先去判断,是否在本地文件已经留有这个特片,如果有,那就直接读取进行对比。从打印日志看到,最耗时的就是对人脸特征的提取。
后期如果我把特征时放入数据缓存,那就可以大大的提升检测的速度。
【程序的改进】
现在将示例的程改进如下:
#include <opencv2/opencv.hpp>
#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include "face_detect.h"
#include "face_alignment.h"
#include "face_recognition.h"
#include <fstream>
#include <string>
#include <vector>
using namespace cv;
bool save_feature(const std::string& filename, const float* feature, int dim) {
std::ofstream outfile(filename, std::ios::binary);
if (!outfile) {
printf("无法创建特征文件: %s\\n", filename.c_str());
return false;
}
outfile.write(reinterpret_cast<const char*>(&dim), sizeof(int));
outfile.write(reinterpret_cast<const char*>(feature), dim * sizeof(float));
outfile.close();
printf("特征已保存到: %s\\n", filename.c_str());
return true;
}
bool load_feature(const std::string& filename, float* feature, int& dim) {
std::ifstream infile(filename, std::ios::binary);
if (!infile) {
printf("无法打开特征文件: %s\\n", filename.c_str());
return false;
}
infile.read(reinterpret_cast<char*>(&dim), sizeof(int));
if (dim != 512) {
printf("特征维度不匹配: %d != 512\\n", dim);
infile.close();
return false;
}
infile.read(reinterpret_cast<char*>(feature), dim * sizeof(float));
infile.close();
printf("特征已从 %s 加载\\n", filename.c_str());
return true;
}
std::string get_feature_filename(const std::string& image_filename) {
size_t pos = image_filename.find_last_of(".");
if (pos != std::string::npos) {
return image_filename.substr(0, pos) + ".feat";
}
return image_filename + ".feat";
}
int main(int argc, char **argv)
{
rknn_context detect_ctx, recognition_ctx;
std::vector<det> result1, result2;
int ret;
struct timeval start;
struct timeval end;
float time_use=0;
if( argc != 3)
{
printf("./face_recognition_demo xxx.jpg xxx.jpg\\n");
return -1;
}
cv::Mat src_1, src_2;
src_1 = cv::imread(argv[1], 1);
src_2 = cv::imread(argv[2], 1);
printf("face detect init!\\n");
ret = face_detect_init(&detect_ctx, "./face_detect.model");
if( ret < 0)
{
printf("face_detect_init fail! ret=%d\\n", ret);
return -1;
}
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 -1;
}
std::string feat_file1 = get_feature_filename(argv[1]);
std::string feat_file2 = get_feature_filename(argv[2]);
float feature_1[512], feature_2[512];
int dim1, dim2;
bool load_success1 = load_feature(feat_file1, feature_1, dim1);
if (!load_success1) {
printf("未找到特征文件或加载失败,执行特征提取\\n");
face_detect_run(detect_ctx, src_1, result1);
if (result1.empty()) {
printf("在图像1中未检测到人脸\\n");
return -1;
}
Point2f points1[5];
for (int j = 0; j < (int)result1[0].landmarks.size(); ++j)
{
points1[j].x = (int)result1[0].landmarks[j].x;
points1[j].y = (int)result1[0].landmarks[j].y;
}
Mat face_algin_1 = face_alignment(src_1, points1);
gettimeofday(&start,NULL);
face_recognition_run(recognition_ctx, &face_algin_1, &feature_1);
gettimeofday(&end,NULL);
time_use=(end.tv_sec-start.tv_sec)*1000000+(end.tv_usec-start.tv_usec);
printf("特征1提取时间: %f ms\\n",time_use/1000);
save_feature(feat_file1, feature_1, 512);
}
bool load_success2 = load_feature(feat_file2, feature_2, dim2);
if (!load_success2) {
printf("未找到特征文件或加载失败,执行特征提取\\n");
face_detect_run(detect_ctx, src_2, result2);
if (result2.empty()) {
printf("在图像2中未检测到人脸\\n");
return -1;
}
Point2f points2[5];
for (int j = 0; j < (int)result2[0].landmarks.size(); ++j)
{
points2[j].x = (int)result2[0].landmarks[j].x;
points2[j].y = (int)result2[0].landmarks[j].y;
}
Mat face_algin_2 = face_alignment(src_2, points2);
face_recognition_run(recognition_ctx, &face_algin_2, &feature_2);
save_feature(feat_file2, feature_2, 512);
}
float similarity = face_recognition_comparison(feature_1, feature_2, 512);
printf("人脸相似度: %f\\n", similarity);
if (similarity > 0.7) {
printf("判定为同一人\\n");
} else {
printf("判定为不同人\\n");
}
face_detect_release(detect_ctx);
face_recognition_release(recognition_ctx);
return 0;
}
【效果检则】
root@EASY-EAI-ORIN-NANO:/home/orin-nano/Desktop/nfs/GitHub/EASY-EAI-Toolkit-3576/Demos/algorithm-face_recognition/Release# ./test-face-recognition 1.jpg 2.jpg
face detect init!
model input num: 1, output num: 3
face recognition init!
无法打开特征文件: 1.feat
未找到特征文件或加载失败,执行特征提取
特征1提取时间: 12.867000 ms
特征已保存到: 1.feat
无法打开特征文件: 2.feat
未找到特征文件或加载失败,执行特征提取
特征已保存到: 2.feat
人脸相似度: 0.615940
判定为不同人
root@EASY-EAI-ORIN-NANO:/home/orin-nano/Desktop/nfs/GitHub/EASY-EAI-Toolkit-3576/Demos/algorithm-face_recognition/Release# ./test-face-recognition 1.jpg 2.jpg
face detect init!
model input num: 1, output num: 3
face recognition init!
特征已从 1.feat 加载
特征已从 2.feat 加载
人脸相似度: 0.615940
判定为不同人
root@EASY-EAI-ORIN-NANO:/home/orin-nano/Desktop/nfs/GitHub/EASY-EAI-Toolkit-3576/Demos/algorithm-face_recognition/Release# ./test-face-recognition 1.jpg 3.jpg
face detect init!
model input num: 1, output num: 3
face recognition init!
特征已从 1.feat 加载
无法打开特征文件: 3.feat
未找到特征文件或加载失败,执行特征提取
特征已保存到: 3.feat
人脸相似度: -0.079318
判定为不同人
root@EASY-EAI-ORIN-NANO:/home/orin-nano/Desktop/nfs/GitHub/EASY-EAI-Toolkit-3576/Demos/algorithm-face_recognition/Release# ./test-face-recognition 1.jpg 3.jpg
face detect init!
model input num: 1, output num: 3
face recognition init!
特征已从 1.feat 加载
特征已从 3.feat 加载
人脸相似度: -0.079318
判定为不同人
root@EASY-EAI-ORIN-NANO:/home/orin-nano/Desktop/nfs/GitHub/EASY-EAI-Toolkit-3576/Demos/algorithm-face_recognition/Release# ./test-face-recognition 1.jpg 2.jpg
face detect init!
model input num: 1, output num: 3
face recognition init!
特征已从 1.feat 加载
特征已从 2.feat 加载
人脸相似度: 0.615940
判定为不同人
root@EASY-EAI-ORIN-NANO:/home/orin-nano/Desktop/nfs/GitHub/EASY-EAI-Toolkit-3576/Demos/algorithm-face_recognition/Release# ./test-face-recognition liu1.jpg liu2.jpg
face detect init!
model input num: 1, output num: 3
face recognition init!
无法打开特征文件: liu1.feat
未找到特征文件或加载失败,执行特征提取
特征1提取时间: 12.842000 ms
特征已保存到: liu1.feat
无法打开特征文件: liu2.feat
未找到特征文件或加载失败,执行特征提取
特征已保存到: liu2.feat
人脸相似度: 1.000000
判定为同一人
root@EASY-EAI-ORIN-NANO:/home/orin-nano/Desktop/nfs/GitHub/EASY-EAI-Toolkit-3576/Demos/algorithm-face_recognition/Release# ./test-face-recognition liu1.jpg liu2.png
face detect init!
model input num: 1, output num: 3
face recognition init!
特征已从 liu1.feat 加载
特征已从 liu2.feat 加载
人脸相似度: 1.000000
判定为同一人
root@EASY-EAI-ORIN-NANO:/home/orin-nano/Desktop/nfs/GitHub/EASY-EAI-Toolkit-3576/Demos/algorithm-face_recognition/Release# ./test-face-recognition liu1.png liu2.png
face detect init!
model input num: 1, output num: 3
face recognition init!
特征已从 liu1.feat 加载
特征已从 liu2.feat 加载
人脸相似度: 1.000000
判定为同一人
root@EASY-EAI-ORIN-NANO:/home/orin-nano/Desktop/nfs/GitHub/EASY-EAI-Toolkit-3576/Demos/algorithm-face_recognition/Release# ./test-face-recognition 1.png liu2.png
[ WARN:0@0.008] global ./modules/imgcodecs/src/loadsave.cpp (239) findDecoder imread_('1.png'): can't open/read file: check file path/integrity
face detect init!
model input num: 1, output num: 3
face recognition init!
特征已从 1.feat 加载
特征已从 liu2.feat 加载
人脸相似度: 0.024156
判定为不同人
root@EASY-EAI-ORIN-NANO:/home/orin-nano/Desktop/nfs/GitHub/EASY-EAI-Toolkit-3576/Demos/algorithm-face_recognition/Release#
【总结】
从上面我们可以看出提取一张图片的特征值为12ms,如果我们需要从大量的数据库中读取图片,那这样就可以大大的提升。