DEV Community

Cover image for Comparing 3 Face Recognition Approaches in Python: Eigenfaces (PCA), LBPH, and DeepFace
Pavan Kumar Sadashiv
Pavan Kumar Sadashiv

Posted on

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

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.


🧠 Overview of the 3 Approaches

  1. Eigenfaces (PCA-based Representation)

    • Extracts principal components (eigenvectors) of the face distribution.
    • Pros: Fast and computationally lightweight.
    • Cons: Very sensitive to lighting, pose, and requires uniform image sizes.
  2. LBPH (Local Binary Pattern Histograms)

    • Analyzes local pixel neighborhoods by thresholding surrounding pixels against the center pixel.
    • Pros: Much more robust to illumination changes than Eigenfaces because it looks at relative local textures rather than global pixel intensities.
    • Cons: Less accurate than deep learning on unconstrained real-world faces.
  3. DeepFace (Deep Learning-based Recognition)

    • Uses pre-trained Convolutional Neural Networks (CNNs) like VGG-Face, FaceNet, or ArcFace to generate high-dimensional face embeddings.
    • Pros: State-of-the-art accuracy, highly robust to lighting and angles, and requires zero explicit training for verification.
    • Cons: Requires heavier dependencies (TensorFlow/Keras) and more compute.

🛠️ Prerequisites & Avoiding 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'
Enter fullscreen mode Exit fullscreen mode

How to Set Up Properly:

  1. Use Google Colab (Recommended for zero setup) or a Local Python Environment (VS Code, PyCharm, Jupyter).
  2. Install opencv-contrib-python instead of standard opencv-python. Standard OpenCV does not include the 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
Enter fullscreen mode Exit fullscreen mode

💻 Option 1: Clean & Simple Exam/Lab Script (With Local Images)

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:

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']}")
Enter fullscreen mode Exit fullscreen mode

☁️ Option 2: Self-Contained Google Colab Script (No Image Uploads Needed!)

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'])
Enter fullscreen mode Exit fullscreen mode

📊 Final Comparison Summary

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.

💡 Key Takeaway

  • If you are building on an ultra-low-power embedded device without a GPU, LBPH offers a great balance of speed and lighting resilience.
  • For academic understanding of dimensionality reduction in computer vision, Eigenfaces (PCA) is a classic starting point.
  • For production applications where accuracy and robustness are top priorities, DeepFace wins hands down.

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

Top comments (0)