最近一直在忙课程,老师让我看看他的论文也没放在心上。总算闲下来,看了他在人脸识别方面的相关论文,拿出一篇放在博客上跟大家共同分析下。在看以下内容前,首先要阅读下徐勇老师的这篇论文

A Two-Phase Test Sample Sparse Representation Method for Use With Face Recognition;当前人脸识别方面最热的方法就是稀疏表示方法(sparse represent),其主要思想是利用线性的或者非线性的表示方法将检查样本用训练样本表示出来,训练样本前的系数为代表比重,选取比重较大的训练样本所属的类来标记测试样本。这种方法在某些模式识别中效果较好,但是其原理并不明确,没有很好的理论基础,所以就方法的科学性而言相对欠缺。徐老师提出两步法,第一步利用所有训练样本来标示出测试样本,并提取M近邻训练样本;第二步利用第一步中提取的M近邻样本表出测试样本,选取代表比重大的训练样本所属于的类来标记测试样本。

关于该方法的理论,希望大家去下载论文阅读,这里就不在多说,重点在于算法的实现上:算法中将实现分为两步,第一步是用所有训练样本表示出测试样本,可以用SVD来计算出系数阵,但在这之前要通过PCA或者LDA的方法给特征向量降维;

opencv中PCA有现成的方法,具体代码如下(我的风格是先给出代码,在代码中介绍实现逻辑)

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>#include <fstream>
#include <sstream>using namespace cv;
using namespace std;//将给出的图像回归为值域在0~255之间的正常图像Mat norm_0_255(const Mat& src) {// 构建返回图像矩阵
    Mat dst;switch(src.channels()) {case 1://根据图像通道情况选择不同的回归函数cv::normalize(src, dst, 0, 255, NORM_MINMAX, CV_8UC1);break;case 3:cv::normalize(src, dst, 0, 255, NORM_MINMAX, CV_8UC3);break;default:src.copyTo(dst);break;}return dst;
}// 将一副图像的数据转换为Row Matrix中的一行;这样做是为了跟opencv给出的PCA类的接口对应//参数中最重要的就是第一个参数,表示的是训练图像样本集合Mat asRowMatrix(const vector<Mat>& src, int rtype, double alpha = 1, double beta = 0) {// 样本个数size_t n = src.size();// 如果样本为空,返回空矩阵if(n == 0)return Mat();// 样本的维度size_t d = src[0].total();// 构建返回矩阵
    Mat data(n, d, rtype);// 将图像数据复制到结果矩阵中for(int i = 0; i < n; i++) {//如果数据为空,抛出异常
        if(src[i].empty()) {string error_message = format("Image number %d was empty, please check your input data.", i);CV_Error(CV_StsBadArg, error_message);}// 图像数据的维度要是d,保证可以复制到返回矩阵中if(src[i].total() != d) {string error_message = format("Wrong number of elements in matrix #%d! Expected %d was %d.", i, d, src[i].total());CV_Error(CV_StsBadArg, error_message);}// 获得返回矩阵中的当前行矩阵:Mat xi = data.row(i);// 将一副图像映射到返回矩阵的一行中:if(src[i].isContinuous()) {src[i].reshape(1, 1).convertTo(xi, rtype, alpha, beta);} else {src[i].clone().reshape(1, 1).convertTo(xi, rtype, alpha, beta);}}return data;
}int main(int argc, const char *argv[]) {// 训练图像集合vector<Mat> db;// 本例中使用的是ORL人脸库,可以自行在网上下载    //将数据读入到集合中db.push_back(imread("s1/1.pgm", IMREAD_GRAYSCALE));db.push_back(imread("s1/2.pgm", IMREAD_GRAYSCALE));db.push_back(imread("s1/3.pgm", IMREAD_GRAYSCALE));db.push_back(imread("s2/1.pgm", IMREAD_GRAYSCALE));db.push_back(imread("s2/2.pgm", IMREAD_GRAYSCALE));db.push_back(imread("s2/3.pgm", IMREAD_GRAYSCALE));db.push_back(imread("s3/1.pgm", IMREAD_GRAYSCALE));db.push_back(imread("s3/2.pgm", IMREAD_GRAYSCALE));db.push_back(imread("s3/3.pgm", IMREAD_GRAYSCALE));db.push_back(imread("s4/1.pgm", IMREAD_GRAYSCALE));db.push_back(imread("s4/2.pgm", IMREAD_GRAYSCALE));db.push_back(imread("s4/3.pgm", IMREAD_GRAYSCALE));// 将训练数据读入到数据集合中,实现PCA类的接口Mat data = asRowMatrix(db, CV_32FC1);// PCA中设定的主成分的维度,这里我们设置为10维度int num_components = 10;// 构建一份PCA类
    PCA pca(data, Mat(), CV_PCA_DATA_AS_ROW, num_components);// 复制PCA方法获得的结果Mat mean = pca.mean.clone();Mat eigenvalues = pca.eigenvalues.clone();Mat eigenvectors = pca.eigenvectors.clone();// 平均脸:imshow("avg", norm_0_255(mean.reshape(1, db[0].rows)));// 前三个训练人物的特征脸imshow("pc1", norm_0_255(pca.eigenvectors.row(0)).reshape(1, db[0].rows));imshow("pc2", norm_0_255(pca.eigenvectors.row(1)).reshape(1, db[0].rows));imshow("pc3", norm_0_255(pca.eigenvectors.row(2)).reshape(1, db[0].rows));// Show the images:waitKey(0);// Success!return 0;
}

以上代码中主要用到的opencv函数介绍:

Mat Mat::reshape(int cn, int rows=0)const

  opencv手册上的解释为:Changes the shape and/or the number of channels of a 2D matrix without copying the data.

参数cn:新的通道数;如果cn值为0表示变换前后通道数不变

参数rows:新的行数;如果rows值为0表示变换后矩阵的行数不变

该函数会为当前矩阵创建一个新的矩阵头(指针),新的矩阵拥有不同的尺寸或者不同的通道数,其优点在于运算复杂度为O(1),不用复制矩阵数据.正是因为不用复制数据,所以在转变过程中要保证原数据矩阵在数据上的连续性(这里的连续性是相对于原矩阵来说)为了更好的说明,举个例子:

std::vector<Point3f> vec;//一个3D数据点的集合
...
Mat pointMat = Mat(vec). // 将这个三维向量集合转换为矩阵,复制度为O(1);实际上形成的矩阵为一个N*1的3通道图像阵
                             reshape(1). // 用reshape方法将其映射为N*3的1通道图像阵,同样运算复杂度为O(1)

boolMat::isContinuous() const


       opencv手册上的解释:Reports whether the matrix is continuous or not.

如果矩阵元素相对于原始矩阵在元素存储上是连续的,行与行之间没有间隙,那么就返回true否则就返回false;很显然如果是1*1或者1*N矩阵,那么其返回值永远是true。这个矩阵的连续性比较晦涩,我们看下该方法的可替代方法的实现

// 替代 Mat::isContinuous()的方法
bool myCheckMatContinuity(const Mat& m)
{
return m.rows == 1 || m.step == m.cols * m.elemSize();//如果矩阵只有一行就不会出现行与行之间的间断;如果为多行,矩阵的步阶应该是列数*元素尺寸
}

voidMat::convertTo(OutputArraym, intrtype, doublealpha=1, doublebeta=0)const

  该函数其实是对原Mat的每一个值做一个线性变换。参数1为目的矩阵,参数2为目d矩阵的类型,参数34变换的系数,看完下面的公式就明白了:

  

PCA::PCA(InputArraydata, InputArraymean, intflags, intmaxComponents=0)

  该构造函数的第一个参数为要进行PCA变换的输入Mat;参数2为该Mat的均值向量;参数3为输入矩阵数据的存储方式,如果其值为CV_PCA_DATA_AS_ROW则说明输入Mat的每一行代表一个样本,同理当其值为CV_PCA_DATA_AS_COL时,代表输入矩阵的每一列为一个样本;最后一个参数为该PCA计算时保留的最大主成分的个数。如果是缺省值,则表示所有的成分都保留。

MatPCA::project(InputArrayvec)const

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

MatPCA::backProject(InputArrayvec)const

  一般调用backProject()函数前需调用project()函数,因为backProject()函数的参数vec为经过PCA投影降维过后的矩阵。 因此backProject()函数的作用就是用vec来重构原始数据集(关于该函数的本质数学实现暂时还不是很了解)。

  另外PCA类中还有几个成员变量,mean,eigenvectors, eigenvalues等分别对应着原始数据的均值,协方差矩阵的特征值和特征向量。

获得的结果如下:

avrageface

            

EignFace

OK,我们已经可以获得ORL数据库中每个人物的PCA特征脸,下一步也是我们下一节要研究的就是用训练样本表示出测试样本,从而找到M近邻样本;

转载于:https://www.cnblogs.com/zcftech/archive/2013/04/13/3017411.html

Opencv+C++之人脸识别相关推荐

  1. python dlib opencv人脸识别准确度_基于dlib和opencv库的人脸识别

    基于dlib和opencv库的人脸识别 需下载68个特征点的人脸检测模型: http://dlib.net/files/ 文件名为shape_predictor_68_face_landmarks.d ...

  2. 基于 OpenCV + Python 的人脸识别上课签到系统

    目录 前言 安装第三方库 第一步:采集人脸图像 (1)修改姓名学号 (2)运行capture_face.py (3)采集人脸图像 (4)查看采集到的人脸图像 第二步:训练模型 第三步:识别签到 (1) ...

  3. OpenCV+百度云人脸识别项目及源码

    OpenCV+百度云人脸识别项目及源码 1.需要的硬件环境 虚拟机 带有摄像头的电脑 2.整体项目的框架 用Opencv识别人脸,上传百度云进行识别对比 3.虚拟机上需要装的库 sudo apt-ge ...

  4. 【优秀课设】基于OpenCV的Python人脸识别、检测、框选(遍历目录下所有照片依次识别 视频随时标注)

    基于OpenCV的Python人脸识别.检测.框选 (遍历目录下所有照片依次识别 视频随时标注) 移步: https://blog.csdn.net/weixin_53403301/article/d ...

  5. 【毕业设计/课程设计】基于opencv的高精度人脸识别考勤系统设计与实现

    文章目录 0 项目说明 1 需求分析 2 总体设计 3 详细设计 4 程序运行结果测试与分析 5 实验心得 6 项目源码 0 项目说明 基于opencv的高精度人脸识别考勤系统设计与实现 提示:适合用 ...

  6. 使用openCV进行视频人脸识别

    视频人脸识别系列 第一篇 使用openCV进行视频人脸识别 第二篇 使用虹软SDK进行视频人脸识别 第三篇 使用虹软SDK进行视频人脸比对 文章目录 视频人脸识别系列 前言 一.环境搭建 开发环境 配 ...

  7. Python+OpenCv实现AI人脸识别身份认证系统(2)——人脸数据采集、存储

    原 Python+OpenCv实现AI人脸识别身份认证系统(2)--人脸数据采集.存储 2019年07月02日 08:47:52 不脱发的程序猿 阅读数 602更多 所属专栏: 人脸识别身份认证系统设 ...

  8. 基于Opencv快速实现人脸识别(图片识别)

    两个文件夹,一个为训练数据集,一个为测试数据集,训练数据集中有两个文件夹0和1,之前看一些资料有说这里要遵循"slabel"命名规则,但后面处理起来比较麻烦,因为目前opencv接 ...

  9. C++ OpenCV相片视频人脸识别统计人数

    C++ OpenCV相片视频人脸识别统计人数 如需远程调试,可加QQ905733049由专业技术人员远程协助! 运行代码如下: #include <iostream> #include&l ...

  10. 基于Opencv快速实现人脸识别(完整版)

    上篇博客:https://blog.csdn.net/beyond9305/article/details/92844258严格来说标题是有误的,只是单纯地对人脸进行了检测,而并非识别,opencv内 ...

最新文章

  1. DedeCMS筛选简单实现方法不改后台源文件
  2. Behavioral模式之Memento模式
  3. spring boot 热更新,热部署
  4. 最全三大框架整合(使用映射)——IDeptService.java
  5. 「浏览器插件」非常好用的JSON-View
  6. linux关闭交互模式,linux – 关闭cp(copy)命令的交互模式(cp:overwrite?)
  7. Pycharm如何导入python包
  8. 指针大小为什么与类型无关?
  9. e站app里站hosts_硬核干货区 | E站的国际站运营知识星球上线啦
  10. 整理Java基础知识--数组2
  11. 服务应用突然宕机了?别怕,Dubbo 帮你自动搞定服务隔离!
  12. 高通QCC3005_datasheet
  13. 一台 ZXHN F650(GPON ONU) 学习小记
  14. CCF计算机软件能力认证试题练习:201903-2 二十四点
  15. 用360安全卫士检查计算机中是否有木马,你的电脑真的做好防护了吗?使用360安全卫士木马查杀一键扫描就知道...
  16. 机器学习之朴素贝叶斯分类算法
  17. PhalApi框架新手脱坑笔记(一)
  18. python三阶魔方_三阶魔方自动求解及动态可视化matlab代码
  19. 玩客云添加到我的计算机,电脑连接玩客云访问玩客云硬盘空间传输文件方法
  20. mega2560电脑识别不到端口后_mega2560在win7 64位安装驱动成功

热门文章

  1. 获取分辨率函数是什么_什么是像素?分辨率是什么?
  2. ubuntu 14.04 android jdk,Ubuntu 14.04 安裝 jdk8u20 並配置環境變量 安裝Android Studio
  3. 计算机制作乘法表格,excel表格乘法怎么用,excel表格怎么算乘法
  4. redhat enterprise linux5.4.iso,版本有RedHat Enterprise Linux(RHEL)5.4/5.5/5.8/6.0/6.3 ISO镜像文件下载地址...
  5. [zz]c++可变参数函数使用
  6. 百度MapAPI之地理编码
  7. 猫猫学iOS之小知识之xcode6自己主动提示图片插件 KSImageNamed的安装
  8. WhatsApp拟取消服务订阅年费
  9. 内存延续分派治理方法
  10. Android模拟器安装apk应用程序