opencv4.5.4以前
VideoCapture函数可以读入视频流(可以是摄像头也可以是视频文件)
如果读摄像头,VideoCapture函数返回的对象可以用isOpened函数检测开启状态
VideoCapture函数返回的对象可以用read函数读取,read返回一个flag(是否还有帧)和frame(当前帧的图像)
release函数释放摄像头
cv.face.LBPHFaceRecognizer_create()函数可以返回一个人脸识别器对象
人脸识别器对象调用train函数可进行训练(写入人脸数据),需要两个参数,第一个是人脸区域图数组(可通过分类器的detectMultiScale函数获得),第二个是人脸对应的id数组(一个int数组)
人脸识别器对象调用write函数可将训练数据写入一个文件(通常是yml格式)
人脸识别器对象调用read函数读取数据文件
人脸识别器对象调用predict函数对人脸数据进行识别,输入的参数为人脸区域图像(可通过分类器的detectMultiScale函数获得),返回可能对应的id和置信度。
opencv4.5.4以及之后的新方法
最新发布的OpenCV 4.5.4版本收录了一个基于深度学习神经网络的人脸模块(以下称“OpenCV DNN Face”),包括人脸检测(使用模型YuNet,由OpenCV China团队贡献)和人脸识别(使用模型SFace,由北京邮电大学邓伟洪教授课题组贡献)。
使用OpenCV DNN Face的API,只需几行代码便可以完成整个人脸检测和人脸识别处理,极大的方便了开发。
# 人脸检测 img = cv.imread("path/to/image")#读取图片 faceDetector = cv.FaceDetectorYN.create("/path/to/model", "", img.shape[:2])#创建人脸检测器 faces = faceDetector.detect(image)#进行人脸检测,并返回人脸区域 # 人脸识别 recognizer = cv.FaceRecognizerSF.create(recog_model_path, "" )#创建人脸识别器 aligned_face = recognizer.alignCrop(img, faces[1][0])#对齐人脸 feature = recognizer.feature(aligned_face)#获取人脸特征 cosine_score = recognizer.match(feature1, feature2, 0)#特征之间进行比对,返回置信度
调用FaceDetectorYN和FaceRecognizerSF这两个模块之前,需要准备两个ONNX的模块文件:
用于FaceDetectorYN的YuNet模块文件:Face Detection
用于FaceRecognizerSF的sFace模块文件:Face Recognition
OpenCV基于深度学习的人脸检测FaceDetectorYN
人脸检测是返回一张图像中人脸的位置(x1, y1)和大小(w, h),如下图所示(原图片来自于WIDER Face数据集)。

C++下人脸检测API(FaceDetectorYN类)的使用方式:
// 第一步:导入相关头文件 #include <opencv2/imgproc.hpp> // cv::imread #include <opencv2/objdetect.hpp> // cv::FaceDetectorYN & cv::FaceRecognizerSF using namespace cv; int main() { // 第二步:读取图像 Mat img = imread("path/to/image"); // 第三步:初始化FaceDetectorYN Ptr<FaceDetectorYN> faceDetector = FaceDetectorYN::create(modelPath, "", img.size()); // 第四步:检测人脸并将结果保存到一个Mat中 Mat faces; faceDetector->detect(image, faces); // faces是一个nx15的二维Mat,每一行分别是: // [x1, y1, w, h, x_re, y_re, x_le, y_le, x_nt, y_nt, x_rcm, y_rcm, x_lcm, y_lcm, score] // 其中,x1, y1是人脸框左上角坐标,w和h分别是人脸框的宽和高;{x, y}_{re, le, nt, rcm, lcm}分别是人脸右眼瞳孔、左眼瞳孔、鼻尖、右嘴角和左嘴角的坐标;score是该人脸的得分。 }
OpenCV基于深度学习的人脸识别FaceRecognizerSF
人脸预处理
将检测到的人脸输入人脸识别模型前,通常需要先进行人脸对齐。人脸对齐利用检测部分提取到的关键点,与给定关键点之间计算变换矩阵,使用仿射变换对人脸进行变换,以减轻人脸尺度、姿态等对人脸特征提取的性能的影响。
C++下人脸对齐部分API(FaceRecognizerSF类)的使用方式:
// 初始化FaceRecognizerSF Ptr<FaceRecognizerSF> faceRecognizer = FaceRecognizerSF::create(recog_model_path, ""); // 在人脸检测部分的基础上, 对齐检测到的首个人脸(faces.row(0)), 保存至aligned_face。 Mat aligned_face; faceRecognizer->alignCrop(image, faces.row(0), aligned_face);
人脸特征提取
狭义的人脸识别模型仅作用于人脸特征提取过程。近年来,深度学习促进了人脸识别的发展,深度人脸识别模型也因其优越的性能得到了广泛应用。深度人脸识别模型的训练离不开大规模训练集、高效的神经网络结构和训练损失函数。深度人脸识别模型在经过良好训练后,可以将预处理过的人脸图像转换为深度人脸特征用于后续的特征匹配。
OpenCV DNN Face所集成的深度人脸识别模型是由超球面损失函数监督、在百万名人数据集上训练的MobileNet轻量模型。将百万名人数据集,在使用基于元学习的自适应标签噪声清洗算法进行数据清洗后,用于训练人脸识别模型,提高了人脸识别模型的性能。
模型结构使用了MobileNet,其利用深度可分离卷积减小了模型体积与计算量,是一种适用于移动设备的轻量级深度卷积神经网络。训练损失函数使用了SFace, SFace在超球面上施加由S型曲线控制的类内和类间约束以有裕度地减小类内距离而增大类间距离,从而训练出对训练噪声鲁棒的深度人脸模型,提高了人脸识别模型的性能。
人脸识别模型以尺寸为3*112*112的人脸图像对齐作为输入,输出维度为128维的人脸特征。
C++下特征提取部分API(FaceRecognizerSF类)的使用方式:
// 在上文的基础上, 获取对齐人脸的特征feature。 Mat feature; faceRecognizer->feature(aligned_face, feature);
人脸特征比对
对于不同人脸图像的人脸特征,经过人脸特征比对求出特征之间的距离,以确定不同人脸图像是否属于同一身份。当使用consine距离时,值越大,则人脸越相似身份越接近;当使用normL2距离时,值越小,则人脸越相似身份越接近。
C++下特征比对部分API(FaceRecognizerSF类)的使用方式:
// 在上文的基础上, 比对两张人脸的特征feature1,feature2以确认身份。 // 使用consine距离作为指标 double cos_score = faceRecognizer->match(feature1, feature2, FaceRecognizerSF::DisType::FR_COSINE); if(cos_score >= cosine_similar_thresh) { // the same identity } else { // different identities } // 使用normL2距离作为指标 double L2_score = faceRecognizer->match(feature1, feature2, FaceRecognizerSF::DisType::FR_NORM_L2); if(L2_score <= l2norm_similar_thresh) { // the same identity } else { // different identities }
参考文章
1.一天搞定人脸识别项目!学不会up直接下跪!(python+opencv)_哔哩哔哩_bilibili
2.使用OpenCV内置深度学习人脸模块,几行代码轻松完成人脸检测和识别 – 知乎 (zhihu.com)
3.OpenCV: DNN-based Face Detection And Recognition
4.OpenCV: cv::FaceRecognizerSF Class Reference