人臉識別算法-特征臉方法(Eigenface)及python實現


原文地址:人臉識別算法-特征臉方法(Eigenface)及python實現

特征臉方法基本是將人臉識別推向真正可用的第一種方法,了解一下還是很有必要的。特征臉用到的理論基礎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

這就意味着,如果 uiTTT的一個特征向量,則 vi = TuiS 的一個特征向量。

看懂上面這一些需要一些線性代數知識,這里的T 就是上面的偏差矩陣, 反正到最后我們得TTT的一個特征向量,再用T與之相乘就是協方差矩陣的特征向量。而此時我們求的特征向量是11368*15的矩陣,

每一行(11368*1)如果變成圖像大小矩陣(98*116)的話,都可以看做是一個新人臉,被稱為特征臉。這里展現我試驗中的其中一部分。


4.主成分分析。在求得的特征向量和特征值中,越大的特征值對於我們區分越重要,也就是我們說的主成分,我們只需要那些大的特征值對應的特征向量,

而那些十分小甚至為0的特征值對於我們來說,對應的特征向量幾乎沒有意義。在這里我們通過一個閾值selecthr來控制,當排序后的特征值的一部分相加

大於該閾值時,我們選擇這部分特征值對應的特征向量,此時我們剩下的矩陣是11368*M',M'根據情況在變化。 這樣我們不僅減少了計算量,而且保留

了主成分,減少了噪聲的干擾。

 

5.這一步就是開始進行人臉識別了。此時我們導入一個新的人臉,我們使用上面主成分分析后得到的特征向量,來求得一個每一個特征向量對於導入人臉的權重向量


 

這里的就是上面第2步求得的平均圖像。 特征向量其實就是訓練集合的圖像與均值圖像在該方向上的偏差,通過未知人臉在特征向量的投影,我們就可以知道未知人臉與平均圖像在不同方向上的差距。此時我們用上面第2步我們求得的偏差矩陣的每一行做這樣的處理,每一行都會得到一個權重向量。我們利用求得的歐式距離來判斷未知人臉與第k張訓練人臉之間的差距。

在這里因為我假設我要識別的未知人肯定是訓練集合里有的,所以我通過比較,選擇最小的k就是這個人臉對應的訓練集合的臉。實際上,一般都是設定距離閾值,當距離小於閾值時說明要判別的臉和訓練集內的第k個臉是同一個人的。當遍歷所有訓練集都大於閾值時,根據距離值的大小又可分為是新的人臉或者不是人臉的兩種情況。根據訓練集的不同,閾值設定並不是固定的。


最后附上python代碼,這里的 ReconginitionVector函數就是求得特征向量的函數,就是按照上面說的順序寫下來的,judgeFace函數用來識別人臉。(大家可以借鑒一下,如果發現有什么不對的歡迎討論):

 

#coding:utf-8
from numpy import *
from numpy import linalg as la
import cv2
import os

def loadImageSet(add):
    FaceMat = mat(zeros((15,98*116)))
    j =0
    for i in os.listdir(add):
        if i.split('.')[1] == 'normal':
            try:
                img = cv2.imread(add+i,0)
            except:
                print 'load %s failed'%i
            FaceMat[j,:] = mat(img).flatten()
            j += 1
    return FaceMat

def ReconginitionVector(selecthr = 0.8):
    # step1: load the face image data ,get the matrix consists of all image
    FaceMat = loadImageSet('D:\python/face recongnition\YALE\YALE\unpadded/').T
    # step2: average the FaceMat
    avgImg = mean(FaceMat,1)
    # step3: calculate the difference of avgimg and all image data(FaceMat)
    diffTrain = FaceMat-avgImg
    #step4: calculate eigenvector of covariance matrix (because covariance matrix will cause memory error)
    eigvals,eigVects = linalg.eig(mat(diffTrain.T*diffTrain))
    eigSortIndex = argsort(-eigvals)
    for i in xrange(shape(FaceMat)[1]):
        if (eigvals[eigSortIndex[:i]]/eigvals.sum()).sum() >= selecthr:
            eigSortIndex = eigSortIndex[:i]
            break
    covVects = diffTrain * eigVects[:,eigSortIndex] # covVects is the eigenvector of covariance matrix
    # avgImg 是均值圖像,covVects是協方差矩陣的特征向量,diffTrain是偏差矩陣
    return avgImg,covVects,diffTrain

def judgeFace(judgeImg,FaceVector,avgImg,diffTrain):
    diff = judgeImg.T - avgImg
    weiVec = FaceVector.T* diff
    res = 0
    resVal = inf
    for i in range(15):
        TrainVec = FaceVector.T*diffTrain[:,i]
        if  (array(weiVec-TrainVec)**2).sum() < resVal:
            res =  i
            resVal = (array(weiVec-TrainVec)**2).sum()
    return res+1

if __name__ == '__main__':

    avgImg,FaceVector,diffTrain = ReconginitionVector(selecthr = 0.9)
    nameList = ['01','02','03','04','05','06','07','08','09','10','11','12','13','14','15']
    characteristic = ['centerlight','glasses','happy','leftlight','noglasses','rightlight','sad','sleepy','surprised','wink']

    for c in characteristic:

        count = 0
        for i in range(len(nameList)):

            # 這里的loadname就是我們要識別的未知人臉圖,我們通過15張未知人臉找出的對應訓練人臉進行對比來求出正確率
            loadname = 'D:\python/face recongnition\YALE\YALE\unpadded\subject'+nameList[i]+'.'+c+'.pgm'
            judgeImg = cv2.imread(loadname,0)
            if judgeFace(mat(judgeImg).flatten(),FaceVector,avgImg,diffTrain) == int(nameList[i]):
                count += 1
        print 'accuracy of %s is %f'%(c, float(count)/len(nameList))  # 求出正確率

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM