1.FERET人脸数据库 -
由FERET项目创建,包含1万多张多姿态和光照的人脸图像,是人脸识别领域应用最广泛的人脸数据库之一.其中的多数人是西方人,每个人所包含的人脸图像的变化比较单一
2.CMU-PIE人脸数据库
由美国卡耐基梅隆大学创建,包含68位志愿者的41,368张多姿态,光照和表情的面部图像.其中的姿态和光照变化图像也是在严格控制的条件下采集的,目前已经逐渐成为人脸识别领域的一个重要的测试集合
3.YALE人脸数据库
由耶鲁大学计算视觉与控制中心创建,包含15位志愿者的165张图片,包含光照,表情和姿态
的变化.
4. YALE人脸数据库B
包含了10个人的5,850幅多姿态,多光照的图像.其中的姿态和光照变化的图像都是在严格控制的条件下采集的,主要用于光照和姿态问题的建模与分析.由于采集人数较少,该数据库的进一步应用受到了比较大的限制
5. MIT人脸数据库
由麻省理工大学媒体实验室创建,包含16位志愿者的2,592张不同姿态,光照和大小的面部图像.
6. ORL人脸数据库
由剑桥大学AT&T实验室创建,包含40人共400张面部图像,部分志愿者的图像包括了姿态,
表情和面部饰物的变化.该人脸库在人脸识别研究的早期经常被人们采用,但由于变化模式较少,多数系统的识别率均可以达到90%以上,因此进一步利用的价值已经不大.
7. BioID人脸数据库
包含在各种光照和复杂背景下的1521张灰度面部图像,眼睛位置已经被手工标注。
人脸识别技术在中国的发展起步于上世纪九十年代末,经历了技术引进-专业市场导入-技术完善-技术应用-各行业领域使用等五个阶段。目前,国内的人脸识别技术已经相对发展成熟,该技术越来越多的被推广到安防领域,延伸出考勤机、门禁机等多种产品,可以全面覆盖煤矿、楼宇、银行、军队、社会福利保障、电子商务及安全防务等领域,人脸识别的全面应用时代已经到来。
人脸识别技术介绍
(1)人脸识别技术流程
人脸识别的技术原理主要包括三大步骤:首先是建立人脸图像数据库,其次是通过各种方式来获得当前要进行识别的目标人脸图像,最后是将目标人脸图像与数据库中既有的人脸图像进行比对和筛选,其技术流程如下:
(2)人脸识别的主要方法
人脸识别技术是一个跨越多个学科领域知识的高端技术研究工作,涉及图像处理、生理学、心理学、模式识别等知识,目前比较常见的人脸识别方法包括基于特征脸的方法、基于几何特征的方法、基于深度学习的方法、基于支持向量机的方法以及其他综合方法。
(3)常用人脸数据库介绍
目前世界较为常用的人脸数据库包括:ERET人脸数据库、CMU
Multi-PIE人脸数据库、YALE人脸数据库、YALE人脸数据库B、MIT人脸数据库、ORL人脸数据库、BioID人脸数据库、年龄识别数据集IMDB-WIKI等。
人脸识别技术具有非侵犯性
人脸识别是生物特征识别技术的一个重要方向,不同的生物识别技术在细分技术上各具优势,人脸识别技术是非接触和不需要主动接受的,具有非侵犯性。此外,人们对这种技术的排斥心理最小,因此人脸识别技术是一种最友好的生物特征识别技术,并且图像采集可以由安防中的摄像头完成,不需要重新再布置新的采集设备。
行业技术环境十分活跃
截至2019年底,在soopat专利搜索引擎上以“人脸识别”为关键词检索得到20208项专利申请记录,行业技术环境十分活跃。
从申请年来看,2010-2018年,我国专利申请数逐年增长,2018年增加至5618项,为近年来最高,2019年我国人脸识别相关专利申请数达3024项。
从公开年来看,我国最早于2002年有人脸识别相关专利公开,当年公开数量为1项,随后专利公开量保持快速增长态势,2019年我国人脸识别相关专利公开数量为6700项。
中国人脸识别技术发明专利申请量超六成
在超2万项的人脸识别技术专利中,发明专利的申请量最多,达12407项,占比为61.40%其次为实用新型专利,占比为24.76%。
G06K专利申请量过万
从我国人脸识别相关热门专利技术申请分布领域来看,G06K(数据识别、数据表示、记录载体、记录载体的处理)申请量最多,达10134项其次为G07C(时间登记器或出勤登记器、登记或指示机器的运行、产生随机数、投票或彩票设备、未列入其他类目的核算装置),申请数量为1302项。
人脸识别错误率逐年降低
经过了40多年的发展,人脸识别技术取得了长足进步,根据LFW测试成绩显示,目前最优的系统在千万分之一的误报下达到识别准确率准确率已经超过99.8%,甚至超过了人类的识别程度,错误验证率也控制在0.2%以下。
即使是采用评测标准最严格的FRVT测试,根据2019年7月3日NIST公布的FRVT最新报告显示了全球人脸识别算法的最高水平可以做到在千万分之一误报率下,漏报率降低于0.3%,这意味着千万分位误报下的识别准确率已经超过99%,人脸识别技术的不断进步无疑会促进其在更广泛范围内的应用。
应用场景广泛,安防和考勤门禁占比较高
目前,人脸识别在考勤/门禁领域的应用最为成熟,约占行业市场的40%左右安防作为人脸识别最早应用的领域之一,其市场份额占比在30%左右金融作为人脸识别未来重要的应用领域之一,其市场规模在逐步扩大,目前约占行业的20%。
三维人脸识别技术是发展主流
从人脸识别技术发展过程来看,未来三维人脸识别是人脸识别主要技术手段,二维人脸识别只是人脸识别发展的过度阶段。实验结果显示,二维人脸识别系统在人脸左右偏转达到40度识别率迅速下降到50%以下而采用三维人脸识别后,识别率可以提高至少10-20个百分点。
以上数据来源于前瞻产业研究院《中国人脸识别行业市场前瞻与投资战略规划分析报告》。
友情提示,要看懂代码前,你得先知道OpenCV的安装和配置,会用C++,用过一些OpenCV函数。基本的图像处理和矩阵知识也是需要的。[gm:我是箫鸣的注释]由于我仅仅是翻译,对于六级才过的我,肯定有一些翻译错的或者不当的地方,所以请大家纠错。1.1.介绍Introduction
从OpenCV2.4开始,加入了新的类FaceRecognizer,我们可以使用它便捷地进行人脸识别实验。本文既介绍代码使用,又介绍算法原理。(他写的源代码,我们可以在OpenCV的opencv\modules\contrib\doc\facerec\src下找到,当然也可以在他的github中找到,如果你想研究源码,自然可以去看看,不复杂)
目前支持的算法有
Eigenfaces特征脸createEigenFaceRecognizer()
Fisherfaces createFisherFaceRecognizer()
LocalBinary Patterns Histograms局部二值直方图 createLBPHFaceRecognizer()
下面所有的例子中的代码在OpenCV安装目录下的samples/cpp下面都能找到,所有的代码商用或者学习都是免费的。
1.2.人脸识别Face Recognition
对人类来说,人脸识别很容易。文献[Tu06]告诉我们,仅仅是才三天的婴儿已经可以区分周围熟悉的人脸了。那么对于计算机来说,到底有多难?其实,迄今为止,我们对于人类自己为何可以区分不同的人所知甚少。是人脸内部特征(眼睛、鼻子、嘴巴)还是外部特征(头型、发际线)对于人类识别更有效?我们怎么分析一张图像,大脑是如何对它编码的?David Hubel和TorstenWiesel向我们展示,我们的大脑针对不同的场景,如线、边、角或者运动这些局部特征有专门的神经细胞作出反应。显然我们没有把世界看成零散的块块,我们的视觉皮层必须以某种方式把不同的信息来源转化成有用的模式。自动人脸识别就是如何从一幅图像中提取有意义的特征,把它们放入一种有用的表示方式,然后对他们进行一些分类。基于几何特征的人脸的人脸识别可能是最直观的方法来识别人脸。第一个自动人脸识别系统在[Kanade73]中又描述:标记点(眼睛、耳朵、鼻子等的位置)用来构造一个特征向量(点与点之间的距离、角度等)。通过计算测试和训练图像的特征向量的欧氏距离来进行识别。这样的方法对于光照变化很稳健,但也有巨大的缺点:标记点的确定是很复杂的,即使是使用最先进的算法。一些几何特征人脸识别近期工作在文献[Bru92]中有描述。一个22维的特征向量被用在一个大数据库上,单靠几何特征不能提供足够的信息用于人脸识别。
特征脸方法在文献[TP91]中有描述,他描述了一个全面的方法来识别人脸:面部图像是一个点,这个点是从高维图像空间找到它在低维空间的表示,这样分类变得很简单。低维子空间低维是使用主元分析(Principal Component Analysis,PCA)找到的,它可以找拥有最大方差的那个轴。虽然这样的转换是从最佳重建角度考虑的,但是他没有把标签问题考虑进去。[gm:读懂这段需要一些机器学习知识]。想象一个情况,如果变化是基于外部来源,比如光照。轴的最大方差不一定包含任何有鉴别性的信息,因此此时的分类是不可能的。因此,一个使用线性鉴别(Linear Discriminant Analysis,LDA)的特定类投影方法被提出来解决人脸识别问题[BHK97]。其中一个基本的想法就是,使类内方差最小的同时,使类外方差最大。
近年来,各种局部特征提取方法出现。为了避免输入的图像的高维数据,仅仅使用的局部特征描述图像的方法被提出,提取的特征(很有希望的)对于局部遮挡、光照变化、小样本等情况更强健。有关局部特征提取的方法有盖伯小波(Gabor Waelets)([Wiskott97]),离散傅立叶变换(DiscreteCosinus Transform,DCT)([Messer06]),局部二值模式(LocalBinary Patterns,LBP)([AHP04])。使用什么方法来提取时域空间的局部特征依旧是一个开放性的研究问题,因为空间信息是潜在有用的信息。
1.3.人脸库Face Database
我们先获取一些数据来进行实验吧。我不想在这里做一个幼稚的例子。我们在研究人脸识别,所以我们需要一个真的人脸图像!你可以自己创建自己的数据集,也可以从这里(http://face-rec.org/databases/)下载一个。
AT&TFacedatabase又称ORL人脸数据库,40个人,每人10张照片。照片在不同时间、不同光照、不同表情(睁眼闭眼、笑或者不笑)、不同人脸细节(戴眼镜或者不戴眼镜)下采集。所有的图像都在一个黑暗均匀的背景下采集的,正面竖直人脸(有些有有轻微旋转)。
YaleFacedatabase A ORL数据库对于初始化测试比较适合,但它是一个简单的数据库,特征脸已经可以达到97%的识别率,所以你使用其他方法很难得到更好的提升。Yale人脸数据库是一个对于初始实验更好的数据库,因为识别问题更复杂。这个数据库包括15个人(14个男人,1个女人),每一个都有11个灰度图像,大小是320*243像素。数据库中有光照变化(中心光照、左侧光照、右侧光照)、表情变化(开心、正常、悲伤、瞌睡、惊讶、眨眼)、眼镜(戴眼镜或者没戴)。
坏消息是它不可以公开下载,可能因为原来的服务器坏了。但我们可以找到一些镜像(比如 theMIT)但我不能保证它的完整性。如果你需要自己剪裁和校准图像,可以阅读我的笔记(bytefish.de/blog/fisherfaces)。
ExtendedYale Facedatabase B 此数据库包含38个人的2414张图片,并且是剪裁好的。这个数据库重点是测试特征提取是否对光照变化强健,因为图像的表情、遮挡等都没变化。我认为这个数据库太大,不适合这篇文章的实验,我建议使用ORL数据库。
1.3.1. 准备数据
我们从网上下了数据,下了我们需要在程序中读取它,我决定使用CSV文件读取它。一个CSV文件包含文件名,紧跟一个标签。
/path/to/image.ext0
假设/path/to/image.ext是图像,就像你在windows下的c:/faces/person0/image0.jpg。最后我们给它一个标签0。这个标签类似代表这个人的名字,所以同一个人的照片的标签都一样。我们对下载的ORL数据库进行标识,可以获取到如下结果:
./at/s1/1.pgm0
./at/s1/2.pgm0
...
./at/s2/1.pgm1
./at/s2/2.pgm1
...
./at/s40/1.pgm39
./at/s40/2.pgm39
想象我已经把图像解压缩在D:/data/at下面,而CSV文件在D:/data/at.txt。下面你根据自己的情况修改替换即可。一旦你成功建立CSV文件,就可以像这样运行示例程序:
facerec_demo.exe D:/data/at.txt
1.3.2 Creating the CSV File
你不需要手工来创建一个CSV文件,我已经写了一个Python程序来做这事。
[gm:说一个我实现的方法
如果你会cmd命令,或者称DOS命令,那么你打开命令控制台。假设我们的图片放在J:下的Faces文件夹下,可以输入如下语句:
J:\Faces\ORL>dir /b/s *.bmp >at.txt
然后你打开at.txt文件可能看到如下内容(后面的0,1..标签是自己加的):
。。。。
J:\Faces\ORL\s1\1.bmp0
J:\Faces\ORL\s1\10.bmp0
J:\Faces\ORL\s1\2.bmp0
J:\Faces\ORL\s1\3.bmp0
J:\Faces\ORL\s1\4.bmp0
J:\Faces\ORL\s1\5.bmp0
J:\Faces\ORL\s1\6.bmp0
J:\Faces\ORL\s1\7.bmp0
J:\Faces\ORL\s1\8.bmp0
J:\Faces\ORL\s1\9.bmp0
J:\Faces\ORL\s10\1.bmp1
J:\Faces\ORL\s10\10.bmp1
J:\Faces\ORL\s10\2.bmp1
J:\Faces\ORL\s10\3.bmp1
J:\Faces\ORL\s10\4.bmp1
J:\Faces\ORL\s10\5.bmp1
J:\Faces\ORL\s10\6.bmp1
。。。。
自然还有c++编程等方法可以做得更好,看这篇文章反响,如果很多人需要,我就把这部分的代码写出来。(遍历多个文件夹,标上标签)
]
特征脸Eigenfaces
我们讲过,图像表示的问题是他的高维问题。二维灰度图像p*q大小,是一个m=qp维的向量空间,所以一个100*100像素大小的图像就是10,000维的图像空间。问题是,是不是所有的维数空间对我们来说都有用?我们可以做一个决定,如果数据有任何差异,我们可以通过寻找主元来知道主要信息。主成分分析(Principal Component Analysis,PCA)是KarlPearson (1901)独立发表的,而 Harold Hotelling (1933)把一些可能相关的变量转换成一个更小的不相关的子集。想法是,一个高维数据集经常被相关变量表示,因此只有一些的维上数据才是有意义的,包含最多的信息。PCA方法寻找数据中拥有最大方差的方向,被称为主成分。
算法描述Algorithmic Description
令 2 表示一个随机特征,其中 3 .
计算均值向量 4
5
计算协方差矩阵 S
6
计算 的特征值7和对应的特征向量 8 9
对特征值进行递减排序,特征向量和它顺序一致. K个主成分也就是k个最大的特征值对应的特征向量。
x的K个主成份:
10
其中11 .
PCA基的重构:
12
其中 13 .
然后特征脸通过下面的方式进行人脸识别:
A. 把所有的训练数据投影到PCA子空间
B. 把待识别图像投影到PCA子空间
C. 找到训练数据投影后的向量和待识别图像投影后的向量最近的那个。
还有一个问题有待解决。比如我们有400张图片,每张100*100像素大小,那么PCA需要解决协方差矩阵 14的求解,而X的大小是10000*400,那么我们会得到10000*10000大小的矩阵,这需要大概0.8GB的内存。解决这个问题不容易,所以我们需要另一个计策。就是转置一下再求,特征向量不变化。文献 [Duda01]中有描述。
[gm:这个PCA还是自己搜着看吧,这里的讲的不清楚,不适合初学者看]
OpenCV中使用特征脸Eigenfaces in OpenCV
给出示例程序源代码
#include "opencv2/core/core.hpp"
#include "opencv2/contrib/contrib.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
#include <fstream>
#include <sstream>
usingnamespace cv
usingnamespace std
static Mat norm_0_255(InputArray _src) {
Mat src = _src.getMat()
// 创建和返回一个归一化后的图像矩阵:
Mat dst
switch(src.channels()) {
case1:
cv::normalize(_src, dst, 0,255, NORM_MINMAX, CV_8UC1)
break
case3:
cv::normalize(_src, dst, 0,255, NORM_MINMAX, CV_8UC3)
break
default:
src.copyTo(dst)
break
}
return dst
}
//使用CSV文件去读图像和标签,主要使用stringstream和getline方法
staticvoid read_csv(const string&filename, vector<Mat>&images, vector<int>&labels, char separator ='') {
std::ifstream file(filename.c_str(), ifstream::in)
if (!file) {
string error_message ="No valid input file was given, please check the given filename."
CV_Error(CV_StsBadArg, error_message)
}
string line, path, classlabel
while (getline(file, line)) {
stringstream liness(line)
getline(liness, path, separator)
getline(liness, classlabel)
if(!path.empty()&&!classlabel.empty()) {
images.push_back(imread(path, 0))
labels.push_back(atoi(classlabel.c_str()))
}
}
}
int main(int argc, constchar*argv[]) {
// 检测合法的命令,显示用法
// 如果没有参数输入则退出!.
if (argc <2) {
cout <<"usage: "<<argv[0]<<" <csv.ext><output_folder>"<<endl
exit(1)
}
string output_folder
if (argc ==3) {
output_folder = string(argv[2])
}
//读取你的CSV文件路径.
string fn_csv = string(argv[1])
// 2个容器来存放图像数据和对应的标签
vector<Mat>images
vector<int>labels
// 读取数据. 如果文件不合法就会出错
// 输入的文件名已经有了.
try {
read_csv(fn_csv, images, labels)
} catch (cv::Exception&e) {
cerr <<"Error opening file \""<<fn_csv <<"\". Reason: "<<e.msg <<endl
// 文件有问题,我们啥也做不了了,退出了
exit(1)
}
// 如果没有读取到足够图片,我们也得退出.
if(images.size()<=1) {
string error_message ="This demo needs at least 2 images to work. Please add more images to your data set!"
CV_Error(CV_StsError, error_message)
}
// 得到第一张照片的高度. 在下面对图像
// 变形到他们原始大小时需要
int height = images[0].rows
// 下面的几行代码仅仅是从你的数据集中移除最后一张图片
//[gm:自然这里需要根据自己的需要修改,他这里简化了很多问题]
Mat testSample = images[images.size() -1]
int testLabel = labels[labels.size() -1]
images.pop_back()
labels.pop_back()
// 下面几行创建了一个特征脸模型用于人脸识别,
// 通过CSV文件读取的图像和标签训练它。
// T这里是一个完整的PCA变换
//如果你只想保留10个主成分,使用如下代码
// cv::createEigenFaceRecognizer(10)
//
// 如果你还希望使用置信度阈值来初始化,使用以下语句:
// cv::createEigenFaceRecognizer(10, 123.0)
//
// 如果你使用所有特征并且使用一个阈值,使用以下语句:
// cv::createEigenFaceRecognizer(0, 123.0)
//
Ptr<FaceRecognizer>model = createEigenFaceRecognizer()
model->train(images, labels)
// 下面对测试图像进行预测,predictedLabel是预测标签结果
int predictedLabel = model->predict(testSample)
//
// 还有一种调用方式,可以获取结果同时得到阈值:
// int predictedLabel = -1
// double confidence = 0.0
// model->predict(testSample, predictedLabel, confidence)
//
string result_message = format("Predicted class = %d / Actual class = %d.", predictedLabel, testLabel)
cout <<result_message <<endl
// 这里是如何获取特征脸模型的特征值的例子,使用了getMat方法:
Mat eigenvalues = model->getMat("eigenvalues")
// 同样可以获取特征向量:
Mat W = model->getMat("eigenvectors")
// 得到训练图像的均值向量
Mat mean = model->getMat("mean")
// 现实还是保存:
if(argc==2) {
imshow("mean", norm_0_255(mean.reshape(1, images[0].rows)))
} else {
imwrite(format("%s/mean.png", output_folder.c_str()), norm_0_255(mean.reshape(1, images[0].rows)))
}
// 现实还是保存特征脸:
for (int i =0i <min(10, W.cols)i++) {
string msg = format("Eigenvalue #%d = %.5f", i, eigenvalues.at<double>(i))
cout <<msg <<endl
// 得到第 #i个特征
Mat ev = W.col(i).clone()
//把它变成原始大小,为了把数据显示归一化到0~255.
Mat grayscale = norm_0_255(ev.reshape(1, height))
// 使用伪彩色来显示结果,为了更好的感受.
Mat cgrayscale
applyColorMap(grayscale, cgrayscale, COLORMAP_JET)
// 显示或者保存:
if(argc==2) {
imshow(format("eigenface_%d", i), cgrayscale)
} else {
imwrite(format("%s/eigenface_%d.png", output_folder.c_str(), i), norm_0_255(cgrayscale))
}
}
// 在一些预测过程中,显示还是保存重建后的图像:
for(int num_components =10num_components <300num_components+=15) {
// 从模型中的特征向量截取一部分
Mat evs = Mat(W, Range::all(), Range(0, num_components))
Mat projection = subspaceProject(evs, mean, images[0].reshape(1,1))
Mat reconstruction = subspaceReconstruct(evs, mean, projection)
// 归一化结果,为了显示:
reconstruction = norm_0_255(reconstruction.reshape(1, images[0].rows))
// 显示或者保存:
if(argc==2) {
imshow(format("eigenface_reconstruction_%d", num_components), reconstruction)
} else {
imwrite(format("%s/eigenface_reconstruction_%d.png", output_folder.c_str(), num_components), reconstruction)
}
}
// 如果我们不是存放到文件中,就显示他,这里使用了暂定等待键盘输入:
if(argc==2) {
waitKey(0)
}
return0
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)