官方文档:https://docs.opencv.org/3.4.3/dd/d81/facerec_8hpp.html

源代码在 .\opencv_contrib-3.4.3\modules\face\src中

Opencv实现

从OpenCV2.4开始,加入新的类FaceRecognizer,可以用它方便的进行人脸识别实验。

人脸识别的任务也就是两大部分,训练和预测,分别对应着train函数和predict函数,还有对应的数据加载保存函数save和load。

先来说说训练的过程,train函数的两个参数也很简单,训练的图像组vector<Mat>和对应的标签组vector<int>,这个label标签只需保证同一个人的标签相同即可,不需要保证图像的按标签顺序输入。
    对于预测,有两种调用,其中的参数有测试图像、返回的标签值和测试样本和标签样本的相似性。返回的标签值为-1,说明测试样本在训练集中无对应或距离较远。

目前支持的算法有:

  1. Eigenface特征脸   createEigenFaceRecognizer()
  2. Fisherface             createFisherFaceRecognizer()
  3. LBP局部二值直方图    createLBPHFaceRecognizer()

不过这些模块放在contri库中:

    CV_EXPORTS_W Ptr<FaceRecognizer> **createEigenFaceRecognizer**(int num_components = 0, double threshold = DBL_MAX);CV_EXPORTS_W Ptr<FaceRecognizer> **createFisherFaceRecognizer**(int num_components = 0, double threshold = DBL_MAX);CV_EXPORTS_W Ptr<FaceRecognizer> **createLBPHFaceRecognizer**(int radius=1, int neighbors=8,int grid_x=8, int grid_y=8, double threshold = DBL_MAX);
  1. num_components为PCA主成分的维数;threshold:预测时的阈值。主成分这里有一个选取的准则,要根据输入数据的大小而决定,通常认为80维主成分是足够的。除了这两个输入参数外,还有eigenvalues和eigenvectors分别代表特征值和特征向量,mean参数为训练样本的平均值,projections为训练数据的预测值,labels为预测时的阈值。
  2. FisherFace,也有num_components和threshold两个参数和其他5个参数,FisherFace的降维是LDA得到的。特别需要强调的是,EigenFace和FisherFace的训练图像和测试图像都必须是灰度图,而且是经过归一化裁剪过的。
  3. 对于LBPHFace,参数包括半径radius,邻域大小即采样点个数neighbors,x和y方向的单元格数目grid_x,grid_y,还有两个参数histograms为训练数据得到的直方图,labels为直方图对应的标签。这个方法也要求训练和测试的图像是灰度图

from:https://blog.csdn.net/yang_xian521/article/details/7735224


Eigenface

1、PCA类是OpenCV实现主要成分分析的类,在人脸识别等机器学习的项目中大量应用,使用前需要先实例化对象。

函数原型:
PCA(InputArray data, InputArray mean, int flags, int maxComponents = 0);
PCA(InputArray data, InputArray mean, int flags, double retainedVariance);

参数说明:
data:需要PCA的数据,每一行(列)表示一个样本;
mean:平均值;如果矩阵是空的(noArray()),则从数据中计算; 
flags:操作标志,具体参数如下:
                            DATA_AS_ROW :每一行表示一个样本;
                            DATA_AS_COL :每一列表示一个样本;
maxComponents :PCA应保留的最大组件数;默认情况下,所有组件都保留;
retainedVariance:PCA应保留的方差百分比。使用这个参数将让PCA决定保留多少组件,但它将始终保持至少2。

2、PCA::project函数
    该函数的作用是将输入数据vec(该数据是用来提取PCA特征的原始数据)投影到PCA主成分空间中去,返回每一个样本主成分特征组成的矩阵。因为经过PCA处理后,原始数据的维数降低了,因此原始数据集中的每一个样本的维数都变了,由改变后的样本集就组成了本函数的返回值。

函数原型:
Mat project(InputArray vec) const;
参数说明:vec:参与投影(降维)的数据

eigenvalues:特征值

eigenvectors:特征向量

train函数的部分代码:

    // get labelsMat labels = _local_labels.getMat();// observations in rowMat data = asRowMatrix(_src, CV_64FC1);// number of samplesint n = data.rows;// assert there are as much samples as labelsif(static_cast<int>(labels.total()) != n) {String error_message = format("The number of samples (src) must equal the number of labels (labels)! len(src)=%d, len(labels)=%d.", n, labels.total());CV_Error(Error::StsBadArg, error_message);}// clear existing model data_labels.release();_projections.clear();// clip number of components to be validif((_num_components <= 0) || (_num_components > n))_num_components = n;// perform the PCAPCA pca(data, Mat(), PCA::DATA_AS_ROW, _num_components);// copy the PCA results_mean = pca.mean.reshape(1,1); // store the mean vector_eigenvalues = pca.eigenvalues.clone(); // eigenvalues by rowtranspose(pca.eigenvectors, _eigenvectors); // eigenvectors by column// store labels for prediction_labels = labels.clone();// save projectionsfor(int sampleIdx = 0; sampleIdx < data.rows; sampleIdx++) {Mat p = LDA::subspaceProject(_eigenvectors, _mean, data.row(sampleIdx));_projections.push_back(p);}

这里讲一下,从上面代码我们看到使用了LDA(它不是用在FisherFace中的吗,通过看下面FisherFace中LDA的用法,发现两者还是有区别的,其实这里只是用了LDA类中的subspaceProject函数,用于计算投影,实际上,投影的特征向量_eigenvectors不还是PCA求解的主成分向量嘛。这与LDA算法原理无关!!!)

Mat p = LDA::subspaceProject(_eigenvectors, _mean, data.row(sampleIdx));// 作用:映射输入图像到特征空间

      你想啊,对输入m个图像矩阵 m*n,进行PCA,求出前K个最大特征值对应的特征向量,然后用输入的图像矩阵乘以K个特征向量,相当于把图像投影到K个向量上,得到一个特征图。参数_projections存放M个矩阵。

test:

void Eigenfaces::predict(InputArray _src, Ptr<PredictCollector> collector) const {// get dataMat src = _src.getMat();// make sure the user is passing correct dataif(_projections.empty()) {// throw error if no data (or simply return -1?)String error_message = "This Eigenfaces model is not computed yet. Did you call Eigenfaces::train?";CV_Error(Error::StsError, error_message);} else if(_eigenvectors.rows != static_cast<int>(src.total())) {// check data alignment just for clearer exception messagesString error_message = format("Wrong input image size. Reason: Training and Test images must be of equal size! Expected an image with %d elements, but got %d.", _eigenvectors.rows, src.total());CV_Error(Error::StsBadArg, error_message);}// project into PCA subspace 将测试图像投影到特征向量上,得到PMat q = LDA::subspaceProject(_eigenvectors, _mean, src.reshape(1, 1));collector->init(_projections.size());for (size_t sampleIdx = 0; sampleIdx < _projections.size(); sampleIdx++) {//把测试图像的特征图,与之前训练得到的所有图的特征图进行比较double dist = norm(_projections[sampleIdx], q, NORM_L2);//范数,即每个对应像素的差异int label = _labels.at<int>((int)sampleIdx);if (!collector->collect(label, dist))return;//不知道是干嘛的??}
}

2、Fisher face方法(PCA+LDA)

LDA(线性判别分析或称Fisher线性判别),PCA(主成份分析)代码及表情识别中的应用

第八章 采用PCA(主成分分析)或LDA(线性判别分析)的人脸识别(二)

LDA算法原理可参见:人脸识别算法二:Fisherface(LDA)

为了提高识别效率,在对特征向量进行降维的同时还需要寻求更有利用分类的向量。 
      Fisher Fface方法是主成分分析(PCA)与Fisher线性判别分析(FLD Fisher Linear Discriminant Analysis)相结合的算法,算法首先对高维特征样本进行PCA降维,投影到低维特征空间,再采用LDA方法得到最优判别向量。

Fisher线性判别分析: 
     基本思想是计算出使Fisher准则函数达到极值的向量,并将此向量作为最佳投影方向,样本在该方向上进行投影,投影后的特征向量具有类间离散度最大,类内离散度最小特点。将特征向量(直接将图像转换成1*mn)映射到K个低维的向量上(这K个低维的向量就是判别向量),然后判断离哪个类别最近,就属于哪个人的人脸。

train函数的部分源码:

   // get dataMat labels = _lbls.getMat();Mat data = asRowMatrix(src, CV_64FC1);// number of samplesint N = data.rows;// make sure labels are passed in correct shapeif(labels.total() != (size_t) N) {String error_message = format("The number of samples (src) must equal the number of labels (labels)! len(src)=%d, len(labels)=%d.", N, labels.total());CV_Error(Error::StsBadArg, error_message);} else if(labels.rows != 1 && labels.cols != 1) {String error_message = format("Expected the labels in a matrix with one row or column! Given dimensions are rows=%s, cols=%d.", labels.rows, labels.cols);CV_Error(Error::StsBadArg, error_message);}// clear existing model data_labels.release();_projections.clear();// safely copy from cv::Mat to std::vectorstd::vector<int> ll;for(unsigned int i = 0; i < labels.total(); i++) {ll.push_back(labels.at<int>(i));}// get the number of unique classesint C = (int) remove_dups(ll).size();// clip number of components to be a valid numberif((_num_components <= 0) || (_num_components > (C-1)))_num_components = (C-1);// perform a PCA and keep (N-C) componentsPCA pca(data, Mat(), PCA::DATA_AS_ROW, (N-C));// 将样本投影到主成分的特征图最为输入,计算它的LDA向量,构造 LDA on it,注意这里输入的不是原图LDA lda(pca.project(data),labels, _num_components);// 保存total mean vector_mean = pca.mean.reshape(1,1);// store labels_labels = labels.clone();// lda的特征向量lda.eigenvalues().convertTo(_eigenvalues, CV_64FC1);// 计算投影矩阵:pca.eigenvectors * lda.eigenvectors.存放到 _eigenvectors中// Note: OpenCV stores the eigenvectors by row,要先转制gemm(pca.eigenvectors, lda.eigenvectors(), 1.0, Mat(), 0.0, _eigenvectors, GEMM_1_T);// store the projections of the original datafor(int sampleIdx = 0; sampleIdx < data.rows; sampleIdx++) {//把样本图像头像到特征空间_eigenvectors中Mat p = LDA::subspaceProject(_eigenvectors, _mean, data.row(sampleIdx));_projections.push_back(p);}
}

1、LDA   lda(const Mat& src, vector<int> labels,int num_components = 0) :

  1. 第一个为数据集(行排列)
  2. 第二个为int类型的标签数组和第一个数据集相对应
  3. 第三个为默认降维的维度为c-1,c是类别的数量

2、void gemm(InputArray src1, InputArray src2, double alpha, InputArray src3, double gamma, OutputArray dst, int flags=0 )

src1 – 第一个矩阵
src2 – 第二个矩阵 of the same type as src1.
alpha – weight of the matrix product.
src3 – third optional delta matrix added to the matrix product; it should have the same type
as src1 and src2.
beta – weight of src3.
dst – output matrix; it has the proper size and the same type as input matrices.
flags – operation flags:
– GEMM_1_T transposes src1.
– GEMM_2_T transposes src2.
– GEMM_3_T transposes src3

公式    :      alpha*op(src1 )*op(src12) + beta*src13,

现在以为没弄明白的是:Ptr<PredictCollector> collector?????    if (!collector->collect(label, dist))return;是啥意思

from:https://blog.csdn.net/cshilin/article/details/52200627

调用:predicted返回预测的label:

 Ptr<FaceRecognizer> model = createFisherFaceRecognizer();model->train(images, labels);Mat img = imread("person1/2.jpg", CV_LOAD_IMAGE_GRAYSCALE);int predicted = model->predict(img);

总结:EigenFace主要是使用PCA(主成分分析),通过消除数据中的相关性,将高维图像降低到低维空间,训练集中的样本被映射成低维空间中的一点,需要判断测试图片性别时,先将测试图片映射到低维空间中,然后计算离测试图片最近样本点是哪一个,将最近样本点的性别赋值给测试图片;FisherFace主要利用LDA(线性投影分析)的思想,将样本空间中的男女样本投影到过原点的一条直线上,并确保样本在该线上的投影类内距离最小,类间距离最大,从而分离出识别男女的分界线。

LBP

LBP算子也可以用于人脸检测,原理详情参见:https://blog.csdn.net/qq_30815237/article/details/88541546

基于LBP算子的人脸识别算法:

LBP被运用于计算机人脸识别领域时,提取出来的人脸特征通常是以LBP直方图向量进行表达的。 
1. 对预处理后的人脸图像进行分块 
2. 对分块后的各小块图像区域进行LBP特征提取变换 
3. 使用LBP直返图向量作为人脸特征的描述。

一般分块数越多,人脸表达的效果就会越好,但是分块数越多,会直接导致特征向量维数的增加,会增加计算的复杂度。对每个分块计算LBP值的直方图,然后将所有分块直方图进行连接得到最终的直方图特征向量,这个特征向量代表原来的人脸图像,可以用来描述整体图像。

对于这个融合的直方图,我们进行特征分类。  如果训练样本数量越大,分类的效果也会越好,

LBPH的预测进程

预测进程就比较简单了,首先将待查询点图象进行lbp编码并生成空间直方图,然后线性暴力的计算直方图的距离,采用基于直方图的相似性度量的最近邻分类方法来分类,终究输出距离最小的预测种别。部分源码:

   // find 1-nearest neighborminDist = DBL_MAX;minClass = -1;for(size_t sampleIdx = 0; sampleIdx < _histograms.size(); sampleIdx++) {double dist = compareHist(_histograms[sampleIdx], query, CV_COMP_CHISQR);if((dist < minDist) && (dist < _threshold)) {minDist = dist;minClass = _labels.at<int>((int) sampleIdx);}}

OpenCV人脸识别类FaceRecognizer相关推荐

  1. OpenCV学习笔记(五十四)——概述FaceRecognizer人脸识别类contrib

    在最新版的2.4.2中,文档的更新也是一大亮点,refrence manual扩充了200多页的内容,添加了contrib部分的文档.contrib就是指OpenCV中新添加的模块,但又不是很稳定,可 ...

  2. OpenCV 解决人脸识别报错cascade.detectMultiScale error

    OpenCV 解决人脸识别报错cascade.detectMultiScale error python调用OpenCV 实现人脸识别 代码如下: 报错:cascade.detectMultiScal ...

  3. python opencv人脸识别考勤系统的完整源码

    这篇文章主要介绍了python opencv人脸识别考勤系统的完整源码,本文给大家介绍的非常详细,希望对大家的学习或工作具有一定的参考借鉴价值. 代码如下: import wx import wx.g ...

  4. OpenCV — 人脸识别

    前段时间弄过一下人脸识别相关的东西,记录一下 撰写不易,转载需注明出处:http://blog.csdn.net/jscese/article/details/54409627本文来自 [jscese ...

  5. 基于opencv人脸识别

    基于opencv平台实现人脸识别.mac os建议使用pycharm ce 编译器使用Xcode 第一步建立代码运行的环境 打开pycharm ce 终端或者mac 终端 输入pip install ...

  6. opencv 全志_移植opencv人脸识别到全志A10开发板上 +linux3.0内核

    移植opencv人脸识别 libz:    zlib-1.2.3 libjpeg:   jpegsrc.v6b libpng:   libpng-1.2.18 libyasm:   yasm-0.7. ...

  7. opencv 人脸识别_Python学习:基于Opencv来快速实现人脸识别(完整版)

    随着人工智能的日益火热,计算机视觉领域发展迅速,尤其在人脸识别或物体检测方向更为广泛,今天就为大家带来最基础的人脸识别基础,从一个个函数开始走进这个奥妙的世界. 首先看一下本实验需要的数据集,为了简便 ...

  8. matlab做pca人脸识别,[转载]一个修改后的PCA进行人脸识别的Matlab代码,识

    一个修改后的PCA进行人脸识别的Matlab代码,识别率达到88% % calc xmean,sigma and its eigen decomposition allsamples=[];%所有训练 ...

  9. 技术详解:基于人脸识别的 AI 弹幕

    --------点击屏幕右侧或者屏幕底部"+订阅",关注我,随时分享机器智能最新行业动态及技术干货---------- 有时候,弹幕比剧情还精彩,那些脑洞大开.观点鲜明的弹幕,可以 ...

最新文章

  1. 汇编:div 除法指令
  2. skb详细解析【转】
  3. JS学习笔记:防止发生命名冲突
  4. MySQL小表join大表的正确使用姿势(straight_join 关键字的使用)
  5. 详解Python中的JSON以及在Python中使用JSON
  6. 反函数连续性定理 反三角_高中数学:三角函数诱导公式及诱导公式口诀
  7. (28)VHDL实现数码管直译
  8. 基于卷积神经网络的小麦病害识别方法
  9. vscode 调试 PHP 打造PHP本地开发环境
  10. vue实现播放rtmp直播视频流
  11. SSM框架:MyBatis
  12. 什么是像素格式(色彩采样、色度抽样)RGB 4:4:4、(Limit)RGB 4:4:4、Ycbcr 4:4:4、Ycbcr 4:2:2、Ycbcr 4:2:0又是什么?
  13. 《沉默的大多数》 - 王小波
  14. html embed用法
  15. unity2d旋转专攻◤一◢ 角度计算
  16. Anbox 容器管理服务
  17. android canvas 背景图片,Android更改canvas背景颜色而不会丢失任何图纸
  18. STM32初识及运用—GPIO
  19. 铭说 | 内网渗透工具分析——reGeorg
  20. 火车头采集器文章组合聚合

热门文章

  1. mysql罏在十三_MySQL高级知识(十三)——表锁
  2. oracle如何不让表自动建分区,怎么自动创建表空间和表分区
  3. 微软企业库mysql分页存储_使用微软企业库,非分页sql语句得到分页数据方法
  4. fast-planner 安装
  5. mysql参数之innodb_buffer_pool_size大小设置
  6. XAF-列表视图数据访问模式
  7. Codeforces Round #432 B
  8. 网站缓存技术总结( ehcache、memcache、redis对比)
  9. 浏览器访问网页的详细内部过程
  10. Response.Redirect 产生的“正在中止线程”错误