1. 程式人生 > >PCA特徵臉python實現

PCA特徵臉python實現

PCA特徵臉python實現

PCA原理

PCA全名為主成分分析,其主要目的就是尋找一個矩陣,然後把原來的一組帶有相關性的矩陣對映到尋找到的那個矩陣中,達到降維的目的。一般的,如果我們有M個N維向量,想將其變換為由R個N維向量表示的新空間中,那麼首先將R個基按行組成矩陣A,然後將向量按列組成矩陣B,那麼兩矩陣的乘積AB就是變換結果,其中AB的第m列為A中第m列變換後的結果。 這句話就相當於找到了一個R行N列矩陣,然後乘一個N行M列矩陣,這樣就得到了一個R行M列矩陣(其中R<=N),達到降維的目的。其中M和N的含義為,M可以代表樣本個數,而N代表每個樣本的特徵個數,所以最終結果就是把原來N個特徵變為了R個特徵,達到降維目的。

PCA演算法描述

1、構建一個樣本集合 S = { T 1 , T 2

, . . . , T M } S =\{T_1,T_2,...,T_M\}
, S S 可以看做是一個N行M列的矩陣,也就是有M個樣本,每個樣本有N個特徵。其中 T i T_i 是一個向量。
2、0均值化,為了便於計算方差的時候需要減去均值,所以如果本身樣本是零均值的,就方便計算。

m = 1 M i = 1 M T i m = \frac{1}{M}\sum_{i=1}^{M}T_i ,這個是計算均值在python中可以使用

m = T.mean(axis = 1)  

進行計算,其中axis = 1代表按行求均值。
然後 A = T m A = T -m 這個相當於把每個樣本都減去均值,這樣之後就相當於做了0均值化。

3、計算投影矩陣(就是相當於上面的那個R行M列矩陣)
這個投影矩陣其實就是由 A A T A*A^T 矩陣的特徵向量構成,但是由於大多數情況 A A T A*A^T 的維度太大( A A T A*A^T 是N行N列矩陣,如果是一張圖片的話N就代表畫素點個數,所以是相當大的),所以這個時候就利用數學的小技巧轉化為先求 A T A A^T*A 的特徵向量矩陣V,其中V的每一列是一個特徵向量,那麼V是一個M行M列的矩陣,然後我們再從V中取出前R個最大特徵值對應的特徵向量,所以V就變成了M行R列矩陣,然後 C = A V C = AV ,那麼這個C矩陣就是計算出的投影矩陣,C為一個N行R列的矩陣。

img1

4、把原來樣本進行投影

第三步我們得到了一個N行R列的矩陣C,其中每一列是一個特徵向量,但是我們在講PCA原理的時候我們需要一個R行N列的矩陣,每一行是一個特徵向量,所以我們可以使用 C T C^T ,所以我們投影后的樣本變為 P = C T A P = C^T A 其中P就是一個R行M列的矩陣,可以看出已經達到了降維的目的。

python實現特徵臉

特徵臉

特徵臉就是我們上面求得的C矩陣,所謂的基於特徵臉進行的人臉識別,就是先把人臉對映到一個低緯空間,然後再計算對映後的臉之間的距離,把距離最近的兩個特徵臉歸為同一個人的臉。

所以特徵臉的步驟為:

1、載入訓練集中的臉,轉為一個M行N列矩陣T

2、對T進行0均值化

3、找到T的投影矩陣C

4、計算投影后的矩陣P

5、載入一個測試圖片,並利用C矩陣也把其投影為test_P

6、計算test_P和P中每個樣本的距離,選出最近的那個即可

python程式碼

import numpy as np
import cv2 as cv
import os
import tkinter as tk
import tkinter.filedialog
from PIL import Image, ImageTk
IMAGE_SIZE =(50,50)
# 1、載入訓練集中的臉,轉為一個M行N列矩陣T  
def createDatabase(path):
    # 檢視路徑下所有檔案
    TrainFiles = os.listdir(path)
    # 計算有幾個檔案(圖片命名都是以 序號.jpg方式)減去Thumbs.db
    Train_Number = len(TrainFiles) -1
    T = []
    # 把所有圖片轉為1-D並存入T中
    for i in range(1,Train_Number+1):
        image = cv.imread(path+'/'+str(i)+'.jpg',cv.IMREAD_GRAYSCALE)
        image=cv.resize(image,IMAGE_SIZE)
        # 轉為1-D
        image = image.reshape(image.size,1)
        T.append(image)        
    T = np.array(T)
    # 不能直接T.reshape(T.shape[1],T.shape[0]) 這樣會打亂順序,
    T = T.reshape(T.shape[0],T.shape[1])
    return np.mat(T).T   
    
  
def eigenfaceCore(T):
    # 2、對T進行0均值化  
    # 把均值變為0 axis = 1代表對各行求均值
    m = T.mean(axis = 1)
    A = T-m
    L = (A.T)*(A)
    # 計算AT *A的 特徵向量和特徵值V是特徵值,D是特徵向量
    V, D = np.linalg.eig(L)
    L_eig = []
    for i in range(A.shape[1]):
#         if V[i] >1:
            L_eig.append(D[:,i])
    L_eig = np.mat(np.reshape(np.array(L_eig),(-1,len(L_eig))))
    
    #3、找到T的投影矩陣C  
    # 計算 A *AT的特徵向量
    eigenface = A * L_eig
    return eigenface,m,A   
    
    
def recognize(testImage, eigenface,m,A):
    _,trainNumber = np.shape(eigenface)
    # 4、計算投影后的矩陣P   
    # 投影到特徵臉後的
    projectedImage = eigenface.T*(A)
    # 可解決中文路徑不能開啟問題
    testImageArray = cv.imdecode(np.fromfile(testImage,dtype=np.uint8),cv.IMREAD_GRAYSCALE)
    # 轉為1-D
    testImageArray=cv.resize(testImageArray,IMAGE_SIZE)
    testImageArray = testImageArray.reshape(testImageArray.size,1)
    testImageArray = np.mat(np.array(testImageArray))
    differenceTestImage = testImageArray - m
    
    5、載入一個測試圖片,並利用C矩陣也把其投影為test_P  
    projectedTestImage = eigenface.T*(differenceTestImage)
    distance = []
    # 6、計算test_P和P中每個樣本的距離,選出最近的那個即可  
    for i in range(0, trainNumber):
        q = projectedImage[:,i]
        temp = np.linalg.norm(projectedTestImage - q)
        distance.append(temp)
 
    minDistance = min(distance)
    index = distance.index(minDistance)
    cv.imshow("recognize result",cv.imread('./TrainDatabase'+'/'+str(index+1 )+'.jpg',cv.IMREAD_GRAYSCALE))
    cv.waitKey()
    return index+1   
    
    
# 進行人臉識別主程式
def example(filename):
    T = createDatabase('./TrainDatabase')
    eigenface,m,A = eigenfaceCore(T)
    testimage = filename
    print(testimage)
    print(recognize(testimage, eigenface,m,A))   

上面就是全部的基於特徵臉的人臉識別。

後期加了gui介面,以及資料集可以去我的github上下載:https://github.com/coderwangson/Eigenface

參考

[pca原理]http://blog.codinglabs.org/articles/pca-tutorial.html
[特徵臉原理]https://blog.csdn.net/smartempire/article/details/21406005
https://blog.csdn.net/qq_16936725/article/details/51761685
https://blog.csdn.net/zawdd/article/details/8087280
https://www.zhihu.com/question/67157462/answer/251754530
https://bbs.csdn.net/topics/391905372
https://blog.csdn.net/tinym87/article/details/6957438
https://blog.csdn.net/fjdmy001/article/details/78498150?locationNum=1&fps=1
https://blog.csdn.net/Abit_Go/article/details/77938938
https://fishc.com.cn/thread-73738-1-1.html
https://blog.csdn.net/jjjndk1314/article/details/80620139
https://docs.scipy.org/doc/numpy/reference/generated/numpy.linalg.eig.html