导读
本文主要介绍OpenCV4.5.4中人脸识别模块的使用和简易人脸识别系统的搭建,供大家参考。
背景介绍
前几天刚刚更新的OpenCV4.5.4版本将基于DNN的人脸检测和人脸识别添加到modules/objdetect中,具体更新介绍如下:
OpenCV4.5.4更新了!看看都有哪些新功能?
人脸检测使用的是于仕琪老师团队开源的人脸检测库,具体使用可参考往期文章,检测速度和准确率都很不错。
OpenCV DNN人脸检测模块使用步骤演示(基于OpenCV4.5.4)
效果如下:
同时OpenCV4.5.4 新增了DNN人脸识别模块,人脸识别部分的模型是由下面几位贡献者训练提供:
在不同数据集下的准确率和推荐阈值设置:
人脸识别模块使用介绍
DNN人脸识别例程位置:
OpenCV4.5.4_Releaseopencvsourcessamplesdnnface_match.cpp
使用步骤:
① 下载模型文件:
人脸检测模型下载地址:https://github.com/ShiqiYu/libfacedetection.train/tree/master/tasks/task1/onnx
人脸识别模型下载地址:
https://drive.google.com/file/d/1ClK9WiB492c5OZFKveF3XiHCejoOxINW/view
下载好了就是下面两个文件:
② 人脸检测(对人脸图片1和人脸图片2分别做人脸检测):
代码语言:javascript复制String det_onnx_path = "./yunet.onnx";
// Initialize FaceDetector
Ptr<FaceDetectorYN> faceDetector;
faceDetector = FaceDetectorYN::create(det_onnx_path, "", image1.size(), score_thresh, nms_thresh, top_k);
Mat faces_1;
faceDetector->detect(image1, faces_1);
if (faces_1.rows < 1)
{
std::cerr << "Cannot find a face in " << image1_path << "n";
return -1;
}
faceDetector = FaceDetectorYN::create(det_onnx_path, "", image2.size(), score_thresh, nms_thresh, top_k);
Mat faces_2;
faceDetector->detect(image2, faces_2);
if (faces_2.rows < 1)
{
std::cerr << "Cannot find a face in " << image2_path << "n";
return -1;
}
人脸检测效果(获得人脸区域和5点landmark):
③ 人脸裁剪对齐 提取特征:
代码语言:javascript复制// Initialize FaceRecognizerSF
String reg_onnx_path = "./face_recognizer_fast.onnx";
Ptr<FaceRecognizerSF> faceRecognizer = FaceRecognizerSF::create(reg_onnx_path, "");
Mat aligned_face1, aligned_face2;
faceRecognizer->alignCrop(image1, faces_1.row(0), aligned_face1);
faceRecognizer->alignCrop(image2, faces_2.row(0), aligned_face2);
Mat feature1, feature2;
faceRecognizer->feature(aligned_face1, feature1);
feature1 = feature1.clone();
faceRecognizer->feature(aligned_face2, feature2);
feature2 = feature2.clone();
④ 比对人脸特征相似度,判断是否为同一个人:
代码语言:javascript复制double cos_score = faceRecognizer->match(feature1, feature2, FaceRecognizerSF::DisType::FR_COSINE);
double L2_score = faceRecognizer->match(feature1, feature2, FaceRecognizerSF::DisType::FR_NORM_L2);
if(cos_score >= cosine_similar_thresh)
{
std::cout << "They have the same identity;";
}
else
{
std::cout << "They have different identities;";
}
std::cout << " Cosine Similarity: " << cos_score << ", threshold: " << cosine_similar_thresh << ". (higher value means higher similarity, max 1.0)n";
if(L2_score <= l2norm_similar_thresh)
{
std::cout << "They have the same identity;";
}
else
{
std::cout << "They have different identities.";
}
std::cout << " NormL2 Distance: " << L2_score << ", threshold: " << l2norm_similar_thresh << ". (lower value means higher similarity, min 0.0)n";
人脸特征相似度度量有normL2和cosine方法,对应的判断是否为同一人的阈值分别为1.128和0.363,normL2方法小于阈值1.128判定为同一人,cosine方法大于阈值0.363判定为同一人。
代码语言:javascript复制float score_thresh = 0.9f;
float nms_thresh = 0.3f;
double cosine_similar_thresh = 0.363;
double l2norm_similar_thresh = 1.128;
int top_k = 5000;
依照上面步骤,我们很快就可以搭建一个类似下面的人脸对比应用程序:
匹配准确率已足以应对一般应用,比OpenCV原有的FisherFaceRecognizer、LBPHFaceRecognizer和EigenFaceRecognizer准确率都要好。
人脸识别系统搭建
上面介绍的是搭建一个人脸比对应用,那么如何搭建一个人脸识别系统?步骤又是什么?
我们首先要知道人脸识别一般分为1:1和1:N人脸识别。
1:1人脸识别核心就是人脸比对,比如典型的刷卡人脸识别系统,需要在刷卡(比如工牌,包含姓名等信息)后做人脸识别,其实就是去找对应路径下的人脸图片或人脸特征和当前的人脸特征做比对,来校验卡和人是否一致,常用于公司的考勤打卡系统。这种系统相对来说比较简单,前期数据录入是也只需要采集员工信息和图片就可以完成,用上面的人脸比对思路就可以做一个。
1:N人脸识别相较而言就要复杂一些,对算法的准确率和速度都有很高的要求。在拍照的同时,需要完成数据库内大量人脸特征的对比,如果用上述OpenCV DNN人脸比对方法可能有些困难,检测时间问题可以尝试多线程和硬件加速方法。1:N人脸识别常见于小区门禁的人脸识别系统,目前商用系统已较为成熟。
下面是使用OpenCV DNN人脸识别模块做的一个简单视频人脸识别应用,截取舌战群儒片段,选择张昭和诸葛亮图片先提取特征,然后每一帧取比对,判断相似度,标注识别结果:源码素材与其他应用内容讨论,如有需要可加入知识星球中获取。