---
# System prepended metadata

title: Face Recognization

---

# Face Recognization
資工四 410711225 連昱婷
## :memo:方法及步驟
1. 依據資料庫的影像格式，設計一個讀取pgm影像檔的函式。
1. 每張人臉影像均為92x112=10304的灰階影像，讀取後請將其轉為10304x1的向量，即成為一個樣本。
1. 資料庫共含有400張影像（40人，每人10張），訓練時請只用200張（每人取5張）。
1. 利用PCA計算此200張影像的轉換矩陣，設法將維度從10304降至10, 20, 30, 40, 50維
1. 以這些較低維度的樣本訓練出你所學過的任何分類器來進行辨識。
1. 比較不同維度的辨識率，並統計出混淆矩陣。
1. 以降維後的樣本，繼續利用FLD(LDA)找出另一轉換矩陣，利用此矩陣轉換降維後的樣本（毋需降維只須轉換）為有較佳的類別分離度之新樣本。
1. 以前述之辨識器再度評量辨識率以及統計混淆矩陣。

### 混淆矩陣 Confusion Matrix
混淆矩陣常是用來評估模型好壞的方法，判定一個分類模型的表現好壞，混淆矩陣的各項指標會被拿來參考：
* TP(True Positive): 正確預測成功的正樣本
* TN(True Negative): 正確預測成功的負樣本
* FP(False Positive): 錯誤預測成正樣本(實為負樣本)
* FN(False Negative): 錯誤預測成負樣本(沒能預測出來的正樣本)

此作業為使用Logistic Regression分類器撰寫

## :memo:程式碼
```python=
import numpy as np
import os, glob, random, cv2
from sklearn.linear_model import LogisticRegression
import matplotlib.pyplot as plt
from sklearn.metrics import confusion_matrix
from sklearn.decomposition import PCA
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA

#讀取圖像
def load(folder='./att_faces'):  
    trainData = []
    testData = []
    yTrain = []
    yTest = []
    for k in range(40):
        folder2 = os.path.join(folder, 's%d' % (k + 1))
        data = [cv2.imread(d, 0) for d in glob.glob(os.path.join(folder2, '*.pgm'))]
        sample = random.sample(range(10), 5)    #隨機選擇5張圖片訓練
        trainData.extend([data[i].ravel() for i in range(10) if i in sample])
        testData.extend([data[i].ravel() for i in range(10) if i not in sample])
        yTest.extend([k] * (10 - 5))
        yTrain.extend([k] * 5)
    return np.array(trainData), np.array(yTrain), np.array(testData), np.array(yTest)

#作圖畫出混淆矩陣
def plotmatrix(name, dimension, confusion_mat):
    plt.imshow(confusion_mat, interpolation='nearest', cmap=plt.cm.gray)
    plt.title('{} Dimension {}'.format(name, dimension))
    plt.colorbar()
    tick_marks = np.arange(4)
    plt.xticks(tick_marks, tick_marks)
    plt.yticks(tick_marks, tick_marks)
    plt.ylabel('Real label')
    plt.xlabel('Predict label')
    plt.show()

#使用Logistic Regression分類器
def classifer(name, dimension, xTrain, xTest, yTrain, yTest):
    model = LogisticRegression(max_iter=1000) #在測試時報錯內容為上限過小，因此將值擴大至1000
    model.fit(np.array(xTrain), np.float32(yTrain))
    yPredict = model.predict(np.float32(xTest))
    print('%d: 維度%d %s : LSR識別率: %.3f%%' % (dimension/10, dimension,name, (yPredict == np.array(yTest)).mean() * 100))
    return yTest.tolist(), yPredict

def main(dimension):
    xTrain_, yTrain, xTest_, yTest = load()
    #PCA
    pca = PCA(n_components=dimension)
    pca.fit(xTrain_, yTrain)
    xTrain = pca.transform(xTrain_)
    xTest = pca.transform(xTest_)
    result, ans = classifer("PCA", dimension, xTrain, xTest, yTrain, yTest)
    confusion_mat = confusion_matrix(ans, result)
    plotmatrix("PCA", dimension, confusion_mat)
    #LDA
    lda = LDA()
    xTrain = lda.fit_transform(xTrain, yTrain)
    xTest = lda.transform(xTest)
    result, ans = classifer("LDA", dimension, xTrain, xTest, yTrain, yTest)
    confusion_mat = confusion_matrix(ans, result)
    plotmatrix("LDA", dimension, confusion_mat)

if __name__ == '__main__':
    for i in range(10,51,10):
        main(i)
```

## :memo:執行成果
 
![](https://i.imgur.com/eCLWrLf.png)
![](https://i.imgur.com/GbKiEU1.png)
![](https://i.imgur.com/kHs9xc7.png)
![](https://i.imgur.com/cvwBbnu.png)
![](https://i.imgur.com/S9of0Ex.png)
![](https://i.imgur.com/dMeOmCs.png)
![](https://i.imgur.com/F9xcqog.png)
![](https://i.imgur.com/B295xzc.png)
![](https://i.imgur.com/Dp024Hs.png)
![](https://i.imgur.com/oBa27ra.png)
![](https://i.imgur.com/pV0Rp6w.png)

## :memo:結果討論
這份作業我使用的是在機器學習所學到的Logistic Regression作為分類器
使用Logistic Regression作為分類器的選擇是因為：
1. 邏輯回歸對線性關係的擬合效果好
2. 邏輯回歸計算快(優於SVM和iForest)
3. 可以獲得A類跟B類的機率
4. 實務上Logistic Regression執行速度非常快

由上圖顯示擬合效果和辨識率都不錯
根據維度的慢慢提升，LDA版本的表現慢慢高於PCA的表現
不過我想對於實際的應用上可能比較不切實際
因為特徵不多若資料量更龐大時辨識率可能會大幅降低
