人脸识别算法-特征脸方法(Eigenface)及python实现

这几天无聊,正好想起来以前谁说有同学做人脸识别,感觉好高大上,所以找来一些基础的人脸识别算法来自己实现一下,正好锻炼一下numpy的使用。

特征脸方法基本是将人脸识别推向真正可用的第一种方法,了解一下还是很有必要的。特征脸用到的理论基础PCA我在这里就不说了,百度一大堆,主要讲一下实现步骤和自己在用python实现是发现的问题。这里我所使用的训练图片是YALE的人脸数据库点击打开链接,这里面有15位志愿者的165张图片,包含光照,表情和姿态的变化。(我们做实验的时候就会发现,特征脸算法对光照敏感。)在unpadded文件夹下。每张图片的尺寸是98*116。



特征脸实现步骤(大家如果英语好可以看看这个点击打开链接):

1.获取包含M张人脸图像的集合。我们这里使用15张xxx.normal.pgm来作为人脸训练图像,所以这里M=15.我们把导入的图像拉平,

本来是98*116的矩阵,我们拉平也就是一个11368*1的矩阵,然后M张放在一个大矩阵下,该矩阵为11368*15。

2.我们计算平均图像,并获得偏差矩阵为11368*15.平均图像也就把每一行的15个元素平均计算,

这样最后的平均图像就是一个我们所谓的大众脸。然后每张人脸都减去这个平均图像,最后得到。



3.求得的协方差矩阵。并计算的特征值和特征向量。这是标准的PCA算法流程。但是在这里一个很大的问题就是,协方差矩阵的维度会大到无法计算,例如我们这个11368*15的矩阵,它的协方差矩阵是11368*11368,这个计算量非常大,而且储存也很困难,所以有大神推导出了下面的方法:

设 T 是预处理图像的矩阵,每一列对应一个减去均值图像之后的图像。则,协方差矩阵为 S = TTT ,并且对 S 的特征值分解为

\mathbf{Sv}_i = \mathbf{T}\mathbf{T}^T\mathbf{v}_i = \lambda_i \mathbf{v}_i

然而, TTT 是一个非常大的矩阵。因此,如果转而使用如下的特征值分解

\mathbf{T}^T\mathbf{T}\mathbf{u}_i = \lambda_i \mathbf{u}_i

此时,我们发现如果在等式两边乘以T,可得到

\mathbf{T}\mathbf{T}^T\mathbf{T}\mathbf{u}_i = \lambda_i \mathbf{T}\mathbf{u}_i

这就意味着,如果 ui 是 TTT的一个特征向量,则 vi = Tui 是 S 的一个特征向量。

看懂上面这一些需要一些线性代数知识,这里的T 就是上面的偏差矩阵, 反正到最后我们得TTT的一个特征向量,再用T与之相乘就是协方差矩阵的特征向量。而此时我们求的特征向量是11368*15的矩阵,

每一行(11368*1)如果变成图像大小矩阵(98*116)的话,都可以看做是一个新人脸,被称为特征脸。这里展现我试验中的其中一部分。


4.主成分分析。在求得的特征向量和特征值中,越大的特征值对于我们区分越重要,也就是我们说的主成分,我们只需要那些大的特征值对应的特征向量,

而那些十分小甚至为0的特征值对于我们来说,对应的特征向量几乎没有意义。在这里我们通过一个阈值selecthr来控制,当排序后的特征值的一部分相加

大于该阈值时,我们选择这部分特征值对应的特征向量,此时我们剩下的矩阵是11368*M',M'根据情况在变化。 这样我们不仅减少了计算量,而且保留

了主成分,减少了噪声的干扰。

5.这一步就是开始进行人脸识别了。此时我们导入一个新的人脸,我们使用上面主成分分析后得到的特征向量,来求得一个每一个特征向量对于导入人脸的权重向量


这里的就是上面第2步求得的平均图像。 特征向量其实就是训练集合的图像与均值图像在该方向上的偏差,通过未知人脸在特征向量的投影,我们就可以知道未知人脸与平均图像在不同方向上的差距。此时我们用上面第2步我们求得的偏差矩阵的每一行做这样的处理,每一行都会得到一个权重向量。我们利用求得的欧式距离来判断未知人脸与第k张训练人脸之间的差距。

在这里因为我假设我要识别的未知人肯定是训练集合里有的,所以我通过比较,选择最小的k就是这个人脸对应的训练集合的脸。实际上,一般都是设定距离阈值,当距离小于阈值时说明要判别的脸和训练集内的第k个脸是同一个人的。当遍历所有训练集都大于阈值时,根据距离值的大小又可分为是新的人脸或者不是人脸的两种情况。根据训练集的不同,阈值设定并不是固定的。


最后附上python代码,这里的 ReconginitionVector函数就是求得特征向量的函数,就是按照上面说的顺序写下来的,judgeFace函数用来识别人脸。(大家可以借鉴一下,如果发现有什么不对的欢迎讨论):

[python]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. #coding:utf-8  
  2. from numpy import *  
  3. from numpy import linalg as la  
  4. import cv2  
  5. import os  
  6.   
  7. def loadImageSet(add):  
  8.     FaceMat = mat(zeros((15,98*116)))  
  9.     j =0  
  10.     for i in os.listdir(add):  
  11.         if i.split('.')[1] == 'normal':  
  12.             try:  
  13.                 img = cv2.imread(add+i,0)  
  14.             except:  
  15.                 print 'load %s failed'%i  
  16.             FaceMat[j,:] = mat(img).flatten()  
  17.             j += 1  
  18.     return FaceMat  
  19.   
  20. def ReconginitionVector(selecthr = 0.8):  
  21.     # step1: load the face image data ,get the matrix consists of all image  
  22.     FaceMat = loadImageSet('D:\python/face recongnition\YALE\YALE\unpadded/').T  
  23.     # step2: average the FaceMat  
  24.     avgImg = mean(FaceMat,1)  
  25.     # step3: calculate the difference of avgimg and all image data(FaceMat)  
  26.     diffTrain = FaceMat-avgImg  
  27.     #step4: calculate eigenvector of covariance matrix (because covariance matrix will cause memory error)  
  28.     eigvals,eigVects = linalg.eig(mat(diffTrain.T*diffTrain))  
  29.     eigSortIndex = argsort(-eigvals)  
  30.     for i in xrange(shape(FaceMat)[1]):  
  31.         if (eigvals[eigSortIndex[:i]]/eigvals.sum()).sum() >= selecthr:  
  32.             eigSortIndex = eigSortIndex[:i]  
  33.             break  
  34.     covVects = diffTrain * eigVects[:,eigSortIndex] # covVects is the eigenvector of covariance matrix  
  35.     # avgImg 是均值图像,covVects是协方差矩阵的特征向量,diffTrain是偏差矩阵  
  36.     return avgImg,covVects,diffTrain  
  37.   
  38. def judgeFace(judgeImg,FaceVector,avgImg,diffTrain):  
  39.     diff = judgeImg.T - avgImg  
  40.     weiVec = FaceVector.T* diff  
  41.     res = 0  
  42.     resVal = inf  
  43.     for i in range(15):  
  44.         TrainVec = FaceVector.T*diffTrain[:,i]  
  45.         if  (array(weiVec-TrainVec)**2).sum() < resVal:  
  46.             res =  i  
  47.             resVal = (array(weiVec-TrainVec)**2).sum()  
  48.     return res+1  
  49.   
  50. if __name__ == '__main__':  
  51.   
  52.     avgImg,FaceVector,diffTrain = ReconginitionVector(selecthr = 0.9)  
  53.     nameList = ['01','02','03','04','05','06','07','08','09','10','11','12','13','14','15']  
  54.     characteristic = ['centerlight','glasses','happy','leftlight','noglasses','rightlight','sad','sleepy','surprised','wink']  
  55.   
  56.     for c in characteristic:  
  57.   
  58.         count = 0  
  59.         for i in range(len(nameList)):  
  60.   
  61.             # 这里的loadname就是我们要识别的未知人脸图,我们通过15张未知人脸找出的对应训练人脸进行对比来求出正确率  
  62.             loadname = 'D:\python/face recongnition\YALE\YALE\unpadded\subject'+nameList[i]+'.'+c+'.pgm'  
  63.             judgeImg = cv2.imread(loadname,0)  
  64.             if judgeFace(mat(judgeImg).flatten(),FaceVector,avgImg,diffTrain) == int(nameList[i]):  
  65.                 count += 1  
  66.         print 'accuracy of %s is %f'%(c, float(count)/len(nameList))  # 求出正确率  

  • 1
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值