人脸识别之特征脸方法(Eigenface)

人脸识别之特征脸方法(Eigenface)

[email protected]

http://blog.csdn.net/zouxy09

因为需要,花了一点时间写了下经典的基于特征脸(EigenFace)的人脸识别方法的Matlab代码。这里仅把该代码分享出来。其实,在较新版本的OpenCV中已经提供了FaceRecognizer这一个类,里面不仅包含了特征脸EigenFace,还有FisherFace和LBPHFace这三种人脸识别方法,有兴趣的可以参考OpenCV的API手册,里面都有很详细的使用例程了。

一、特征脸

特征脸EigenFace从思想上其实挺简单。就相当于把人脸从像素空间变换到另一个空间,在另一个空间中做相似性的计算。这么说,其实图像识别的基本思想都是一样的,首先选择一个合适的子空间,将所有的图像变换到这个子空间上,然后再在这个子空间上衡量相似性或者进行分类学习。那为什么要变换到另一个空间呢?当然是为了更好的做识别或者分类了。那为什么变换到一个空间就好识别或者分类了呢?因为变换到另一个空间,同一个类别的图像会聚到一起,不同类别的图像会距离比较远,或者在原像素空间中不同类别的图像在分布上很难用个简单的线或者面把他们切分开,然后如果变换到另一个空间,就可以很好的把他们分开了。有时候,线性(分类器)就可以很容易的把他们分开了。那既然人类看起来同类的图像本来就是相似的,不同类的图像就不太相似,那为什么在原始的像素空间他们同类不会很近,不同类不会很远,或者他们为什么不好分开呢?因为图像各种因素的影响,包括光照、视角、背景和形状等等不同,会造成同一个目标的图像都存在很大的视觉信息上的不同。如下图所示。

世界上没有存在任何两片完全相同的叶子,虽然他们都是叶子。万千世界,同一类事物都存在共性,也存在个性,这就是这个世界多彩的原因。那怎么办呢?很自然,只要在我们想要的粒度上把同一类目标的共性找出来就好了,而且这个共性最好和我们要区分的类是不一样的。什么叫我们想要的粒度?我理解和我们的任务相关的。例如我们要区分人和车,那人的共性就是有脸、有手、有脚等等。但如果我们要区分亚洲人和非洲人,那么亚洲人的共性就是黄色皮肤等等。可以试着想象,上帝把世界万物组织成一个树状结构,树的根就是万物之源,下一层可以分成生物和非生物,再下一层将生物分为……(囧,想象不到),直到最底层,万物,你我,为树的一片普通得再普通的叶子。树越往下,粒度越小,分类越细(哈哈,自己乱扯的)。停!废话多了点,跑题了,回到刚才的问题,重头戏来了,要变换到什么空间,才具备上述这种良好类内相似、类间区分的效果?到这,我就只能say sorry了。计算机视觉领域发展了几十年,就为了这一个问题倾注了无数研究者的智慧与心血。当然了,也诞生和孕育了很多经典和有效的解答。(个人理解,上述说的实际上就是特征提取)。从一开始的颜色特征(颜色直方图)、纹理特征(Harr、LBP、HOG、SIFT等)、形状特征等到视觉表达Bag of Words,再到特征学习Deep Learning,技术的发展总能带给人希望,曙光也越来越清晰,但路还很远,是不?

扯太多了,严重离题了。上面说到,特征脸EigenFace的思想是把人脸从像素空间变换到另一个空间,在另一个空间中做相似性的计算。EigenFace选择的空间变换方法是PCA,也就是大名鼎鼎的主成分分析。它广泛的被用于预处理中以消去样本特征维度之间的相关性。当然了,这里不是说这个。EigenFace方法利用PCA得到人脸分布的主要成分,具体实现是对训练集中所有人脸图像的协方差矩阵进行本征值分解,得对对应的本征向量,这些本征向量(特征向量)就是“特征脸”。每个特征向量或者特征脸相当于捕捉或者描述人脸之间的一种变化或者特性。这就意味着每个人脸都可以表示为这些特征脸的线性组合。实际上,空间变换就等同于“搞基”,原始像素空间的基就是单位“基”,经过PCA后空间就是以每一个特征脸或者特征向量为基,在这个空间(或者坐标轴)下,每个人脸就是一个点,这个点的坐标就是这个人脸在每个特征基下的投影坐标。哦噢,说得有点绕。

下面就直接给出基于特征脸的人脸识别实现过程:

1)将训练集的每一个人脸图像都拉长一列,将他们组合在一起形成一个大矩阵A。假设每个人脸图像是MxM大小,那么拉成一列后每个人脸样本的维度就是d=MxM大小了。假设有N个人脸图像,那么样本矩阵A的维度就是dxN了。

2)将所有的N个人脸在对应维度上加起来,然后求个平均,就得到了一个“平均脸”。你把这个脸显示出来的话,还挺帅的哦。

3)将N个图像都减去那个平均脸图像,得到差值图像的数据矩阵Φ。

4)计算协方差矩阵C=ΦΦT。再对其进行特征值分解。就可以得到想要的特征向量(特征脸)了。

5)将训练集图像和测试集的图像都投影到这些特征向量上了,再对测试集的每个图像找到训练集中的最近邻或者k近邻啥的,进行分类即可。

算法说明白了都是不明白的,所以还是得去看具体实现。因此,可以对照下面的代码来弄清楚这些步骤。

另外,对于步骤4),涉及到求特征值分解。如果人脸的特征维度d很大,例如256x256的人脸图像,d就是65536了。那么协方差矩阵C的维度就是dxd=65536x65536。对这个大矩阵求解特征值分解是很费力的。那怎么办呢?如果人脸的样本不多,也就是N不大的话,我们可以通过求解C’=ΦTΦ矩阵来获得同样的特征向量。可以看到这个C’=ΦTΦ只有NxN的大小哦。如果N远远小于d的话,那么这个力气就省得很值了。那为什么求解C’=ΦTΦ矩阵的特征向量可以获得C=ΦΦT的特征向量?万众瞩目时刻,数学以完美舞姿登上舞台。证明如下:

其中,ei是C’=ΦTΦ的第i个特征向量,vi是C=ΦΦT的第i个特征向量,由证明可以看到,vi=Φei。所以通过求解C’=ΦTΦ的特征值分解得到ei,再左乘Φ就得到C=ΦΦT的特征向量vi了。也就是我们想要的特征脸。

二、Matlab实现

下面的代码主要是在著名的人脸识别数据库YaleB中进行实现。用的是裁切后的人脸数据库,可以点击CroppedYale下载。共有38个人的人脸,人脸是在不同的光照下采集的,每个人脸图像是32x32个像素。实验在每一个的人脸图像中随机取5个作为训练图像,剩下的作为测试图像。当然了,实际过程中这个过程需要重复多次,然后得到多次准确率的均值和方差才有参考意义,但下面的demo就不做这个处理了。计算相似性用的是欧氏距离,但编程实现的时候为了加速,用的是简化版,至于如何简化的,考验你的时候到了。

% Face recognition using eigenfaces

close all, clear, clc;

%% 20 random splits
num_trainImg = 5;
showEigenfaces = true;

%% load data
disp(‘loading data...‘);
dataDir = ‘./CroppedYale‘;
datafile = ‘Yale.mat‘;
if ~exist(datafile, ‘file‘)
	readYaleDataset(dataDir, datafile);
end
load(datafile);

%% Five images per class are randomly chosen as the training
%% dataset and remaining images are used as the test dataset
disp(‘get training and testing data...‘);
num_class = size(unique(labels), 2);
trainIdx = [];
testIdx = [];
for i=1:num_class
	label = find(labels == i);
	indice = randperm(numel(label));
	trainIdx = [trainIdx label(indice(1:num_trainImg))];
	testIdx = [testIdx label(indice(num_trainImg+1:end))];
end

%% get train and test data
train_x = double(data(:, trainIdx));
train_y = labels(trainIdx);
test_x = double(data(:, testIdx));
test_y = labels(testIdx);

%% computing eigenfaces using PCA
disp(‘computing eigenfaces...‘);
tic;
[num_dim, num_imgs] = size(train_x);   %% A: #dim x #images
avg_face = mean(train_x, 2); 			 %% computing the average face
X = bsxfun(@minus, train_x, avg_face); %% computing the difference images

%% PCA
if num_dim <= num_imgs
	C = X * X‘;
	[V, D] = eig(C);
else
	C = X‘ * X;
	[U, D] = eig(C);
	V = X * U;
end
eigenfaces = V;
eigenfaces = eigenfaces ./ (ones(size(eigenfaces,1),1) * sqrt(sum(eigenfaces.*eigenfaces)));
toc;

%% visualize the average face
P = sqrt(numel(avg_face));
Q = numel(avg_face) / P;
imagesc(reshape(avg_face, P, Q)); title(‘Mean face‘);
colormap(‘gray‘);

%% visualize some eigenfaces
figure;
num_eigenfaces_show = 9;
for i = 1:num_eigenfaces_show
	subplot(3, 3, i)
	imagesc(reshape(eigenfaces(:, end-i+1), P, Q));
	title([‘Eigenfaces ‘ num2str(i)]);
end
colormap(‘gray‘);

%% transform all training images to eigen space (each column for each image)
disp(‘transform data to eigen space...‘);
X = bsxfun(@minus, train_x, avg_face);
T = eigenfaces‘ * X;

%% transform the test image to eigen space
X_t = bsxfun(@minus, test_x, avg_face);
T_t = eigenfaces‘ * X_t;

%% find the best match using Euclidean distance
disp(‘find the best match...‘);
AB = -2 * T_t‘ * T;       % N x M
BB = sum(T .* T);         % 1 x M
distance = bsxfun(@plus, AB, BB);        % N x M
[score, index] = min(distance, [], 2);   % N x 1

%% compute accuracy
matchCount = 0;
for i=1:numel(index)
	predict = train_y(index(i));
	if predict == test_y(i)
		matchCount = matchCount + 1;
	end
end

fprintf(‘**************************************\n‘);
fprintf(‘accuracy: %0.3f%% \n‘, 100 * matchCount / numel(index));
fprintf(‘**************************************\n‘);

下面是将CroppedYale的图像读入matlab的代码。

function readYaleDataset(dataDir, saveName)
	dirs = dir(dataDir);
	data = [];
	labels = [];
	for i = 3:numel(dirs)
		imgDir = dirs(i).name;
		imgDir = fullfile(dataDir, imgDir);
		imgList = dir(fullfile(imgDir, ‘*.pgm‘));
		for j = 1:numel(imgList)
			imgName = imgList(j).name;
			if strcmp(‘Ambient.pgm‘,  imgName(end-10:end))
				continue;
			end
			im = imread(fullfile(imgDir, imgName));
			if size(im, 3) ==3
				im = rgb2gray(im);
			end
			im = imresize(im, [32 32]);
			im = reshape(im, 32*32, 1);
			data = [data im];
		end
		labels = [labels ones(1, numel(imgList)-1) * (i-2)];
	end
	save(saveName, ‘data‘, ‘labels‘);
end

三、实验结果

首先来个帅帅的平均脸:

然后来9个帅帅的特征脸:

在本实验中,实验结果是30.126%左右。如果加上了某些预处理,这个结果就可以跑到62%左右。只是这个预处理我有点解析不通,所以就没放在demo上了。

本文如果有什么不对的地方,还望大家指正。

时间: 2024-11-03 20:52:53

人脸识别之特征脸方法(Eigenface)的相关文章

人脸识别经典算法一:特征脸方法(Eigenface)

这篇文章是撸主要介绍人脸识别经典方法的第一篇,后续会有其他方法更新.特征脸方法基本是将人脸识别推向真正可用的第一种方法,了解一下还是很有必要的.特征脸用到的理论基础PCA在另一篇博客里:特征脸(Eigenface)理论基础-PCA(主成分分析法) .本文的参考资料附在最后了^_^ 步骤一:获取包含M张人脸图像的集合S.在我们的例子里有25张人脸图像(虽然是25个不同人的人脸的图像,但是看着怎么不像呢,难道我有脸盲症么),如下图所示哦.每张图像可以转换成一个N维的向量(是的,没错,一个像素一个像素

asp.net 虹软 人脸识别 实现刷脸住宿、刷脸签到、刷脸进入等

先看看效果图,我把demo改成自动运行了,暂时借用别人的图片: 最左侧的大图为选择上传的, 中间的小图是大图的脸, 右侧的大图是人脸文件夹中已经存在的,并且相似度较高的一张脸,也就是比对的结果. 先记录下思路,代码整理好再贴出来. 阿里云和腾讯都有人脸识别的接口,但是图片需要上传到他们的服务器, 并且,接口返回的不是我想要的东西,经过千辛万苦,终于找到了虹软, http://www.arcsoft.com.cn/ai/arcface.html 开源就必须赞一个,并且支持自己搭建服务器,正是我需要

虹软人脸识别SDK的接入方法

背景: 虹软的人脸识别还是不错的,在官方注册一个账号,成为开发者,下载SDK的jar包,在开发者中心,找一个demo就可以开始做了,安装里边的逻辑,先看理解代码,然后就可以控制代码,完成自己想要的功能 一:准备工作 注意: 1 sdk的下载,会给你4个jar包和4个秘钥以及1个appid,这个appid是用来绑定你的jar包,使用别人的会造成识别引擎启动失败, 下载文件如下: 这里需要把文件解压并整理,每个引擎的so文件和jar是分开的,所以需要一一解压,然后整理一下 如下: 在项目里建立如下文

实验报告: 人脸识别方法回顾与实验分析 【OpenCV测试方法源码】

趁着还未工作,先把过去做的东西整理下出来~   Github源码:https://github.com/Blz-Galaxy/OpenCV-Face-Recognition (涉及个人隐私,源码不包含测试样本,请谅解~) 对实验结果更感兴趣的朋友请直接看 第5章 [摘要]这是一篇关于人脸识别方法的实验报告.报告首先回顾了人脸识别研究的发展历程及基本分类:随后对人脸识别技术方法发展过程中一些经典的流行的方法进行了详细的阐述:最后作者通过设计实验对比了三种方法的识别效果并总结了人脸识别所面临的困难与

人脸识别考勤机一秒刷脸打卡

人脸识别考勤机 别名:考勤机,人脸识别考勤机,人脸打卡机,可视打卡 颜色:黑色 使用行业:所有企事业单位 优势:人脸识别智能门禁考勤机,智能人脸识别,刷脸打卡,混合光谱识别,安全保障,万人底库,精确识别,配置方便,4步2分钟搞定安装,一秒打卡,快速整理员工考勤 考勤智能终端,考勤数据与钉钉无缝对接,活体检测,防止作弊,安全无忧安装步骤: 1.扫描二维码下载钉钉--扫描机器二维码--或在各大应用市场搜索并下载钉钉App 2.设备连接手机蓝牙--用钉钉再次扫描机器二维码--并打开手机蓝牙配对D2设备

OpenCV人脸识别Eigen算法源码分析

1 理论基础 学习Eigen人脸识别算法需要了解一下它用到的几个理论基础,现总结如下: 1.1 协方差矩阵 首先需要了解一下公式: 共公式可以看出:均值描述的是样本集合的平均值,而标准差描述的则是样本集合的各个样本点到均值的距离之平均.以一个国家国民收入为例,均值反映了平均收入,而均方差/方差则反映了贫富差距,如果两个国家国民收入均值相等,则标准差越大说明国家的国民收入越不均衡,贫富差距较大.以上公式都是用来描述一维数据量的,把方差公式推广到二维,则可得到协方差公式: 协方差表明了两个随机变量之

人脸识别经典算法三:Fisherface(LDA)

Fisherface是由Ronald Fisher发明的,想必这就是Fisherface名字由来.Fisherface所基于的LDA(Linear Discriminant Analysis,线性判别分析)理论和特征脸里用到的PCA有相似之处,都是对原有数据进行整体降维映射到低维空间的方法,LDA和PCA都是从数据整体入手而不同于LBP提取局部纹理特征.如果阅读本文有难度,可以考虑自学斯坦福公开课机器学习或者补充线代等数学知识. 同时作者要感谢cnblogs上的大牛JerryLead,本篇博文基

人脸识别算法初次了解

这是转载别人的帖子,认为好,大家一块学习http://www.cnblogs.com/guoyiqi/archive/2011/07/28/2129300.html 前言 在写此文之前,先扯点东西.我一直在找一个东西,让我思考,让我久久的深陷当中,永久的,不断的思考.现在,我意识到,这个东西即是算法.我一直在找一家合适的公司,能让我的兴趣无比放肆的,自由驰骋. ok,由于在一家公司的面试过程中,面试官提到过这个人脸识别算法,由于在此之前,未曾有过了解,所以,特作此番学习与研究.有不论什么问题,欢

【计算机视觉】OpenCV人脸识别facerec源码分析2——LBPH概述

人脸识别 从OpenCV2.4开始,加入了新的类FaceRecognizer,我们可以使用它便捷地进行人脸识别实验.其源代码可以在OpenCV中的opencv\modules\contrib\doc\facerec\src下找到. 目前支持的算法有: Eigenfaces特征脸createEigenFaceRecognizer() Fisherfaces createFisherFaceRecognizer() Local Binary Patterns Histograms局部二值直方图 cr