# Comparing 3 Face Recognition Approaches in Python: Eigenfaces (PCA), LBPH, and DeepFace

> Source: <https://dev.to/hrlpavan/comparing-3-face-recognition-approaches-in-python-eigenfaces-pca-lbph-and-deepface-ihj>
> Published: 2026-10-25 16:38:56+00:00

Face recognition has evolved significantly—from classical statistical methods like **Eigenfaces (PCA)** and texture-based descriptors like **LBPH (Local Binary Pattern Histograms)** to modern deep learning frameworks like **DeepFace**.

In this post, we will implement and compare all three approaches on a small dataset in Python, test how they hold up against **illumination changes** (e.g., low lighting), and look at how to run the code effortlessly without running into environment issues.

**Eigenfaces (PCA-based Representation)**

**LBPH (Local Binary Pattern Histograms)**

**DeepFace (Deep Learning-based Recognition)**

`ModuleNotFoundError: No module named 'cv2'`
A common mistake when running this code is executing it inside lightweight online compilers (like Programiz or OnlineGDB), which results in:

```
Traceback (most recent call last):
  File "/box/main.py", line 1, in <module>
    import cv2
ModuleNotFoundError: No module named 'cv2'
```

`opencv-contrib-python`` opencv-python`. Standard OpenCV does `cv2.face` module needed for Eigenfaces and LBPH!
Run this in your terminal:

```
pip uninstall opencv-python -y
pip install opencv-contrib-python deepface scikit-learn tf-keras
```

If you have 4 sample face images in your project directory (`p1_1.jpg`, `p1_2.jpg` for Person 0, and `p2_1.jpg`, `p2_2.jpg` for Person 1), here is the cleanest implementation:

``` python
import cv2
import numpy as np
from deepface import DeepFace

# 1. Load and preprocess the small dataset (Resize to 100x100 & Grayscale)
def load_img(path):
    img = cv2.imread(path, cv2.IMREAD_GRAYSCALE)
    return cv2.resize(img, (100, 100))

# Training data: 2 images of Person 0, 1 image of Person 1
train_imgs = [load_img('p1_1.jpg'), load_img('p1_2.jpg'), load_img('p2_1.jpg')]
labels = np.array([0, 0, 1])

# Test data: Another image of Person 1
test_img = load_img('p2_2.jpg')

# Simulate illumination change (reduce brightness by 50%)
dark_test_img = np.clip(test_img * 0.5, 0, 255).astype(np.uint8)
cv2.imwrite('dark_test.jpg', dark_test_img) # Save for DeepFace

# ---------------------------------------------------------
# APPROACH 1: Eigenfaces (PCA-based)
# ---------------------------------------------------------
eigen_model = cv2.face.EigenFaceRecognizer_create()
eigen_model.train(train_imgs, labels)

pred_eigen_norm, _ = eigen_model.predict(test_img)
pred_eigen_dark, _ = eigen_model.predict(dark_test_img)

# ---------------------------------------------------------
# APPROACH 2: LBPH (Local Binary Pattern Histograms)
# ---------------------------------------------------------
lbph_model = cv2.face.LBPHFaceRecognizer_create()
lbph_model.train(train_imgs, labels)

pred_lbph_norm, _ = lbph_model.predict(test_img)
pred_lbph_dark, _ = lbph_model.predict(dark_test_img)

# ---------------------------------------------------------
# APPROACH 3: DeepFace (Deep Learning-based)
# ---------------------------------------------------------
# DeepFace compares images directly without explicit training
df_norm = DeepFace.verify('p2_1.jpg', 'p2_2.jpg', enforce_detection=False)
df_dark = DeepFace.verify('p2_1.jpg', 'dark_test.jpg', enforce_detection=False)

# ---------------------------------------------------------
# OUTPUT & COMPARISON (Expected Label = 1 / True)
# ---------------------------------------------------------
print("--- COMPARISON RESULTS (Target: Person 1) ---")
print(f"1. Eigenfaces | Normal: {pred_eigen_norm == 1} | Dark: {pred_eigen_dark == 1}")
print(f"2. LBPH       | Normal: {pred_lbph_norm == 1} | Dark: {pred_lbph_dark == 1}")
print(f"3. DeepFace   | Normal: {df_norm['verified']} | Dark: {df_dark['verified']}")
```

Don't have sample photos handy? Paste this directly into a **Google Colab** cell. It automatically installs the dependencies and fetches real faces from Scikit-Learn's built-in LFW (Labeled Faces in the Wild) dataset:

```
# Step 1: Install required libraries in Colab
!pip install -q opencv-contrib-python deepface scikit-learn

import cv2
import numpy as np
from deepface import DeepFace
from sklearn.datasets import fetch_lfw_people

# Step 2: Load a small built-in face dataset (No manual image upload needed)
lfw = fetch_lfw_people(min_faces_per_person=10, resize=1.0)
img_p1_1 = (lfw.images[0] * 255).astype(np.uint8) # Person 0, Image 1
img_p1_2 = (lfw.images[1] * 255).astype(np.uint8) # Person 0, Image 2
img_p2_1 = (lfw.images[2] * 255).astype(np.uint8) # Person 1, Image 1 (Train)
test_img = (lfw.images[3] * 255).astype(np.uint8) # Person 1, Image 2 (Test)

# Resize all to 100x100
train_imgs = [cv2.resize(x, (100, 100)) for x in [img_p1_1, img_p1_2, img_p2_1]]
test_img = cv2.resize(test_img, (100, 100))
labels = np.array([0, 0, 1])

# Simulate illumination change (50% darker)
dark_test_img = (test_img * 0.5).astype(np.uint8)

# Save images temporarily for DeepFace (requires RGB/file paths)
cv2.imwrite('train_p2.jpg', cv2.cvtColor(train_imgs[2], cv2.COLOR_GRAY2BGR))
cv2.imwrite('test_norm.jpg', cv2.cvtColor(test_img, cv2.COLOR_GRAY2BGR))
cv2.imwrite('test_dark.jpg', cv2.cvtColor(dark_test_img, cv2.COLOR_GRAY2BGR))

# 1. Eigenfaces (PCA)
eigen = cv2.face.EigenFaceRecognizer_create()
eigen.train(train_imgs, labels)
print("Eigenfaces (Normal, Dark):", eigen.predict(test_img)[0], eigen.predict(dark_test_img)[0])

# 2. LBPH
lbph = cv2.face.LBPHFaceRecognizer_create()
lbph.train(train_imgs, labels)
print("LBPH       (Normal, Dark):", lbph.predict(test_img)[0], lbph.predict(dark_test_img)[0])

# 3. DeepFace
df_norm = DeepFace.verify('train_p2.jpg', 'test_norm.jpg', enforce_detection=False)
df_dark = DeepFace.verify('train_p2.jpg', 'test_dark.jpg', enforce_detection=False)
print("DeepFace   (Normal, Dark):", df_norm['verified'], df_dark['verified'])
```

Here is how the three approaches stack up across key metrics:

| Evaluation Metric | 1. Eigenfaces (PCA) | 2. LBPH | 3. DeepFace | 
|---|---|---|---|
| **Accuracy** | Low to Moderate (struggles with pose and lighting variations). | Moderate to High on small, controlled datasets. | **Very High** (Backed by state-of-the-art CNNs). | 
| **Robustness Under Illumination Changes** | **Poor** — Global pixel intensity changes drastically shift PCA eigenvectors. | **Good** — Local pixel thresholding preserves texture patterns even when darkened. | **Excellent** — Pre-trained on millions of faces across diverse lighting conditions. | 
| **Ease of Implementation** | **Medium** — Requires strictly identical image dimensions and grayscale conversion. | **Easy** — Handles varied sizes and uses the straightforward`cv2.face` API. | **Easiest** — Just 1 line of code (`DeepFace.verify()` ) with no training loop needed. | 

Happy coding! Feel free to drop any questions in the comments below. 👇
