|
1
|
|
|
# -*- coding: utf-8 -* |
|
2
|
|
|
import numpy as np |
|
3
|
|
|
import os |
|
4
|
|
|
import matplotlib.image as mpimg |
|
5
|
|
|
from scipy import misc |
|
6
|
|
|
import argparse |
|
7
|
|
|
|
|
8
|
|
|
# initialize parameters |
|
9
|
|
|
parser = argparse.ArgumentParser(description='PCA ORL') |
|
10
|
|
|
parser.add_argument('--image-scale', type=float, default=0.5, metavar='scale', |
|
11
|
|
|
help='scale rate for image (default: 0.5)') |
|
12
|
|
|
parser.add_argument('--train-per-person', type=int, default=4, metavar='k', |
|
13
|
|
|
help='training number per-person minimal to 1, maximum to 9 (default: 4)') |
|
14
|
|
|
parser.add_argument('--print-feature-face', type=bool, default=False, metavar='feature_face', |
|
15
|
|
|
help='print feature face (default: False)') |
|
16
|
|
|
parser.add_argument('--principal-rate', type=float, default=1, metavar='principal_percent', |
|
17
|
|
|
help='random seed (default: 1)') |
|
18
|
|
|
args = parser.parse_args() |
|
19
|
|
|
|
|
20
|
|
|
scale = args.image_scale |
|
21
|
|
|
k = args.train_per_person |
|
22
|
|
|
feature_face = args.print_feature_face |
|
23
|
|
|
principal_percent = args.principal_rate |
|
24
|
|
|
|
|
25
|
|
|
# covert image to sole vector |
|
26
|
|
|
def img2vector(filename): |
|
27
|
|
|
imgVector = misc.imresize(mpimg.imread(filename), scale).flatten() |
|
28
|
|
|
return imgVector.astype(np.float) |
|
29
|
|
|
|
|
30
|
|
|
# load image from diretion |
|
31
|
|
|
def loadimage(dataSetDir): |
|
32
|
|
|
train_face = np.zeros((40 * k, int(112 * scale) * int(92 * scale))) # image size:112*92 |
|
33
|
|
|
train_face_number = np.zeros(40 * k).astype(np.int8) |
|
34
|
|
|
test_face = np.zeros((40 * (10 - k), int(112 * scale) * int(92 * scale))) |
|
35
|
|
|
test_face_number = np.zeros(40 * (10 - k)).astype(np.int8) |
|
36
|
|
|
for i in np.linspace(1, 40, 40).astype(np.int8): #40 sample people |
|
37
|
|
|
people_num = i |
|
38
|
|
|
for j in np.linspace(1, 10, 10).astype(np.int8): #everyone has 10 different face |
|
39
|
|
|
if j <= k: |
|
40
|
|
|
filename = dataSetDir+'/s'+str(people_num)+'/'+str(j)+'.pgm' |
|
41
|
|
|
img = img2vector(filename) |
|
42
|
|
|
train_face[(i-1)*k+(j-1),:] = img |
|
43
|
|
|
train_face_number[(i-1)*k+(j-1)] = people_num |
|
44
|
|
|
else: |
|
45
|
|
|
filename = dataSetDir+'/s'+str(people_num)+'/'+str(j)+'.pgm' |
|
46
|
|
|
img = img2vector(filename) |
|
47
|
|
|
test_face[(i-1)*(10-k)+(j-k)-1,:] = img |
|
48
|
|
|
test_face_number[(i-1)*(10-k)+(j-k)-1] = people_num |
|
49
|
|
|
|
|
50
|
|
|
return train_face,train_face_number,test_face,test_face_number #tuple |
|
51
|
|
|
|
|
52
|
|
|
# subtract a vector from a matrex |
|
53
|
|
|
def subvector(target_matrix, target_vector): |
|
54
|
|
|
vector4matrix = np.repeat(target_vector, target_matrix.shape[0],axis = 0) |
|
55
|
|
|
target_matrix = target_matrix - vector4matrix |
|
56
|
|
|
return target_matrix |
|
57
|
|
|
|
|
58
|
|
|
# both data subtract mean data of train data |
|
59
|
|
|
def submean(train_data, test_data): |
|
60
|
|
|
mean_data = train_data.mean(axis = 0).reshape(1, train_data.shape[1]) |
|
61
|
|
|
train_data = subvector(train_data, mean_data) |
|
62
|
|
|
test_data = subvector(test_data, mean_data) |
|
63
|
|
|
return train_data,test_data |
|
64
|
|
|
|
|
65
|
|
|
# main program |
|
66
|
|
|
train_face,train_face_number,test_face,test_face_number = loadimage(os.getcwd()+'/att_faces') |
|
67
|
|
|
train_face, test_face = submean(train_face, test_face) |
|
68
|
|
|
|
|
69
|
|
|
# math calculate: the relevant mathematical formula can be found in the doc document |
|
70
|
|
|
# build high-dimensional space |
|
71
|
|
|
cov = np.dot(train_face.T, train_face) |
|
72
|
|
|
# calculate eigenvalues & eigenvectors |
|
73
|
|
|
l, v = np.linalg.eig(cov) |
|
74
|
|
|
# sort eigenvectors by the value of eigenvalues |
|
75
|
|
|
mix = np.vstack((l,v)) |
|
76
|
|
|
mix = mix.T[np.lexsort(mix[::-1,:])].T[:,::-1] |
|
77
|
|
|
v = np.delete(mix, 0, axis = 0) |
|
78
|
|
|
|
|
79
|
|
|
# select the principal components and map face images into high dimensional space |
|
80
|
|
|
v = v[:,0:int(v.shape[1]*principal_percent)] |
|
81
|
|
|
train_face = np.dot(train_face, v) |
|
82
|
|
|
test_face = np.dot(test_face , v) |
|
83
|
|
|
|
|
84
|
|
|
# recognise via measuring educlidean distance in high dimentional space |
|
85
|
|
|
count = 0 |
|
86
|
|
|
for i in np.linspace(0, test_face.shape[0] - 1, test_face.shape[0]).astype(np.int64): |
|
87
|
|
|
sub = subvector(train_face,test_face[i, :].reshape((1,test_face.shape[1]))) |
|
88
|
|
|
dis = np.linalg.norm(sub, axis = 1) |
|
89
|
|
|
fig = np.argmin(dis) |
|
90
|
|
|
if train_face_number[fig] == test_face_number[i]: |
|
91
|
|
|
count = count + 1 |
|
92
|
|
|
correct_rate = count / test_face.shape[0] |
|
93
|
|
|
|
|
94
|
|
|
# show the parameters and results |
|
95
|
|
|
print("Principal rate=", principal_percent * 100, "%, count for", int(v.shape[1]*principal_percent), "principal eigenvectors") |
|
96
|
|
|
print("Correct rate =", correct_rate * 100 , "%") |
|
97
|
|
|
|
|
98
|
|
|
#show feature maps |
|
99
|
|
|
if feature_face == True: |
|
100
|
|
|
import matplotlib.pyplot as plt |
|
101
|
|
|
plt.figure('Feature Maps') |
|
102
|
|
|
r, c = (4, 10) |
|
103
|
|
|
for i in range(r * c): |
|
104
|
|
|
plt.subplot(r,c,i+1) |
|
105
|
|
|
plt.imshow(v[:, i].real.reshape(int(112 * scale), int(92 * scale)), cmap='gray') |
|
106
|
|
|
plt.axis('off') |
|
107
|
|
|
plt.show() |