Face Recognition using Eigenfaces (Python)
I. Introduction
In various fields and in our daily lives, facial recognition (FR) technology has become one of the basic necessities. For example, you can easily unlock your mobile phone only with your face without resorting to other methods, and this is done by comparing a human face to a database of known faces. In this article, we will discuss how we can implement face recognition in Python by using the Eigenface technique.
II. Requirements
- Understanding the dimensionality-reduction method “Principal Component Analysis (PCA)” is very important, so for that, I find this YouTube video very helpful. StatQuest : Principal Component Analysis (PCA) (étape par étape) — YouTube.
- Basic knowledge in linear algebra.
III. The Eigenfaces method
The strategy of the Eigenfaces method consists of efficiently using Principal Component Analysis (PCA) for projecting the face in question in facespace (eigenspace), so we can represent it as a linear combination of eigenvectors called eigenfaces.
IV. Computation of Eigenfaces and application of FR
A. Training phase
1. Obtain face images I = [ I1, I2, I3, ….,Im ] (training faces) and must be centered with the same size (N, N).
2. Represent every image Ii as a vector Γi , Γ = [ Γ1, Γ2, …., Γm]. dim (Ii) = (N, N) and dim (Γi) = (m, N*N)
3. Compute the average face vector: Ψ = (1/m) * Σ_Γi
4. Subtract the mean face from every vector: φ = [ Γ1 - Ψ, Γ2 - Ψ, …,Γm - Ψ] dim(φ) = (m, N*N)
5. Compute the covariance matrix C: C = (1/m) * φφT where φT is the transpose of φ. dim(C) = (m, m)
6. Compute the eigenvectors(eigenfaces) U of C. dim (U) = (K, N*N)
7. Finding the vector of wights Wi for each image vector φi in the database by using this formula:
φi = Σ Wij * Uj (j =1, 2, …, K)
dim (Wi) = (1, K)
WT = [ W1, W2, …, Wm]
dim(W) = (K, m)
B. Testing phase
Let’s consider a query image vector I_query . We subtract the average face Ψ and getting its weights W_query , then comparing the distances between W_query and all W weight vectors, and finally sorting the result in ascending order.
V. Implementation
1. Import Python Libraries
import cv2import mathimport numpy as npimport pandas as pdfrom math import sqrtimport matplotlib.pyplot as pltfrom sklearn.decomposition import PCAfrom sklearn.datasets import fetch_olivetti_facesplt.rcParams.update(plt.rcParamsDefault)plt.rcParams.update({'figure.figsize': (15, 10)})plt.style.use('dark_background')
This function is used for showing the images.
def showImgs(imgs, n_imgs, i_imgs):
n = sqrt(n_imgs)
m = n
p = 1
if n != int(n):
n = int(n)
m = n + 1
print("n, m", n, m)
fig = plt.figure()
for i in i_imgs:
fig.add_subplot(int(n), int(m), p)
plt.imshow(imgs[i], cmap='gray')
plt.axis('off')
p += 1
plt.show()
2. Loading Olivetti dataset
This dataset contains a set of face images taken between April 1992 and April 1994 at AT&T Laboratories Cambridge. There are ten different images of each of 40 distinct subjects. For some subjects, the images were taken at different times, varying the lighting, facial expressions (open / closed eyes, smiling / not smiling), and facial details (glasses / no glasses). All the images were taken against a dark, homogeneous background, with the subjects in an upright, frontal position (with tolerance for some side movement).
faces = fetch_olivetti_faces()
images = faces.images
images.shape
(400, 64, 64)
features = faces.data # features
targets = faces.target # targets
showImgs(images, 100, range(100))
3. Choosing the query image
query_img1 = images[71]
print('the target of this face is :', targets[71])
showImgs([query_img1], 1, [0])
4. Showing all images of the same face
showImgs(images, 10, range(70, 80))
5. Face recognition algorithm application
First, we convert our query image and dataset image each to a single vector, subtracting the average face to keep the specific characteristics of each face.
query_γ1 = query_img1.reshape(-1)
Γ = np.array([I.reshape(-1) for I in images])
Σ_Γi = np.zeros(4096)
for Γi in Γ:
Σ_Γi += Γi
Ψ = (1/400)* Σ_Γi
showImgs([Ψ.reshape(64,64)], 1, [0])
φ1 = query_γ1 - Ψ
Φ = np.array([I - Ψ for I in Γ])
Φ.shape
(400, 4096)
Find the new transformation or the projection of our images in the eigenspace by calculating the eigenfaces.
# Using the PCA algorithm
pca = PCA(svd_solver='full')
The eigenfaces shape:
pca.components_.shape
(400, 4096)
The shape of the original image set:
images.shape
(400, 64, 64)
The shape of the new projection of our image set:
coord.shape
(400, 400)
Choose the first 40 important eigenfaces:
# These lines just for showing the images in (64, 64)format
best_eigenfaces = []
for eigenface in pca.components_[0 : 40]:
best_eigenfaces.append(eigenface.reshape(64, 64))
showImgs(best_eigenfaces, 40, range(40))
best_eigenfaces = pca.components_[0 : 40]
best_eigenfaces.shape
(40, 4096)
weights = []
for i in range(0, 400):
weight = []
for j in range(0, 40):
w = best_eigenfaces[j] @ Φ[i]
weight.append(w)
weights.append(weight)
weights = np.transpose(weights)
weights.shape
(40, 400)
weight1 = best_eigenfaces @ φ1.T
list_dist1 = np.linalg.norm(weights - weight1.reshape(-1, 1), axis = 0)
df1 = pd.DataFrame(list_dist1, columns=['euc dist'])
df1 = df1.sort_values(by=['euc dist'])
df1.head()
df1.index[0:49]
showImgs(images, 49, df1.index[0 : 49])
As we can see from the result for the first 10 faces, the precision is 0.8.
Let's test with another face image.
All available images of the same face:
The search result below gives a precision of 0.9 for the first 10 faces.
VI. Pros and cons
- Easy to implement and computationally less expensive.
- No knowledge (such as facial feature) of the image required (except id).
Limitations:
- Proper centered face is required for training/testing.
- The algorithm is sensitive to lightning, shadows and also scale of face in the image.
- Front view of the face is required for this algorithm to work properly.
VII. Conclusion
In this article we had applied eigenface technique for facial recognition in python.
Reference:
Eigenfaces for recognition | Journal of Cognitive Neuroscience (acm.org)
5.6.1. The Olivetti faces dataset — scikit-learn 0.19.2 documentation