Face detection and recognition are crucial aspects of modern security systems, user authentication, and human-computer interaction. In this tutorial, we’ll walk through a simple yet powerful implementation of real-time face detection and recognition using OpenCV in Python. We will be using the Local Binary Patterns Histograms (LBPH) algorithm, a popular technique for face recognition.
Prerequisites
Before diving into the code, make sure you have the following installed:
- Python 3.x
- OpenCV library:
pip install opencv-python
- NumPy:
pip install numpy
- Pillow:
pip install pillow
(for handling images)
Step 1: Face Dataset Capture Class
import cv2
import os
import urllib.request
class FaceDataset:
"""
A class to capture face images from the webcam and store them in a dataset directory.
"""
def __init__(self, face_id: int, save_path: str='dataset', width: int=640, height: int=480)-> None:
"""
Initializes the FaceDataset object with the provided parameters.
"""
self.face_id = face_id
self.save_path = save_path
self.cam = cv2.VideoCapture(0)
self.cam.set(3, width)
self.cam.set(4, height)
self._download_haarcascade() # Download Haarcascade if not available
self.face_detector = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
self.count = 0
def _download_haarcascade(self) -> None:
"""Downloads the Haarcascade XML file if it does not exist."""
if not os.path.isfile('haarcascade_frontalface_default.xml'):
print("[INFO] Downloading Haarcascade XML file...")
url = "https://github.com/opencv/opencv/raw/master/data/haarcascades/haarcascade_frontalface_default.xml"
urllib.request.urlretrieve(url, "haarcascade_frontalface_default.xml")
print("[INFO] Download complete.")
def capture_faces(self, samples: int=30):
"""
Captures face images from the webcam and stores them in the dataset directory.
"""
print(f"\n Initializing face capture for User {self.face_id}. Please look at the camera...")
while self.count < samples:
ret, img = self.cam.read()
img = cv2.flip(img, -1)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = self.face_detector.detectMultiScale(gray, 1.3, 5)
for (x, y, w, h) in faces:
cv2.rectangle(img, (x, y), (x+w, y+h), (255, 0, 0), 2)
self.count += 1
cv2.imwrite(f"{self.save_path}/User.{self.face_id}.{self.count}.jpg", gray[y:y+h, x:x+w])
cv2.imshow('Face Capture', img)
if cv2.waitKey(100) & 0xff == 27: # Press 'ESC' to exit early
break
print(f"\n{self.count} face samples captured successfully.")
self.cam.release()
cv2.destroyAllWindows()
# Usage Example
if __name__ == "__main__":
face_id = input("\nEnter user ID and press <return>: ")
face_dataset = FaceDataset(face_id)
face_dataset.capture_faces()
Step 2: Face Trainer Class
import cv2
import numpy as np
from PIL import Image
import os
import urllib.request
class FaceTrainer:
"""
A class to train the face recognizer using images stored in a dataset directory.
Attributes:
-----------
dataset_path : str
Path to the dataset directory containing face images.
trainer_path : str
Path to save the trained face recognizer model.
recognizer : cv2.face.LBPHFaceRecognizer
LBPH face recognizer object.
detector : cv2.CascadeClassifier
Haarcascade classifier for face detection.
"""
def __init__(self, dataset_path: str='dataset', trainer_path: str='trainer', cascade_path: str='haarcascade_frontalface_default.xml'):
"""
Initializes the FaceTrainer object with the provided parameters.
"""
self.dataset_path = dataset_path
self.trainer_path = trainer_path
self.recognizer = cv2.face.LBPHFaceRecognizer_create()
self._download_haarcascade(cascade_path)
self.detector = cv2.CascadeClassifier(cascade_path)
def _download_haarcascade(self, cascade_path):
"""Downloads the Haarcascade XML file if it does not exist."""
if not os.path.isfile(cascade_path):
print("[INFO] Downloading Haarcascade XML file...")
url = "https://github.com/opencv/opencv/raw/master/data/haarcascades/haarcascade_frontalface_default.xml"
urllib.request.urlretrieve(url, cascade_path)
print("[INFO] Download complete.")
def _get_images_and_labels(self):
"""Extracts face samples and corresponding IDs from the dataset."""
image_paths = [os.path.join(self.dataset_path, f) for f in os.listdir(self.dataset_path)]
face_samples = []
ids = []
for image_path in image_paths:
PIL_img = Image.open(image_path).convert('L')
img_numpy = np.array(PIL_img, 'uint8')
user_id = int(os.path.split(image_path)[-1].split(".")[1])
faces = self.detector.detectMultiScale(img_numpy)
for (x, y, w, h) in faces:
face_samples.append(img_numpy[y:y+h, x:x+w])
ids.append(user_id)
return face_samples, ids
def train(self):
"""Trains the face recognizer and saves the model to the trainer directory."""
print("\n Training faces. Please wait...")
faces, ids = self._get_images_and_labels()
self.recognizer.train(faces, np.array(ids))
if not os.path.exists(self.trainer_path):
os.makedirs(self.trainer_path)
self.recognizer.write(f'{self.trainer_path}/trainer.yml')
print(f"\n{len(np.unique(ids))} faces trained successfully. Model saved at {self.trainer_path}/trainer.yml")
# Usage Example
if __name__ == "__main__":
face_trainer = FaceTrainer()
face_trainer.train()
Step 3: Face Recognition Class
import cv2
import numpy as np
import urllib.request
class FaceRecognizer:
"""
A class to perform real-time face recognition using a trained LBPH model.
"""
def __init__(self, trainer_path: str='trainer/trainer.yml', cascade_path: str='haarcascade_frontalface_default.xml', names: str=None):
"""
Initializes the FaceRecognizer object with the provided parameters.
"""
if names is None:
names = ['None', 'Marcelo', 'Paula', 'Ilza', 'Z', 'W']
self._download_haarcascade(cascade_path)
self.recognizer = cv2.face.LBPHFaceRecognizer_create()
self.recognizer.read(trainer_path)
self.face_cascade = cv2.CascadeClassifier(cascade_path)
self.names = names
self.font = cv2.FONT_HERSHEY_SIMPLEX
def _download_haarcascade(self, cascade_path: str):
"""Downloads the Haarcascade XML file if it does not exist."""
if not os.path.isfile(cascade_path):
print("[INFO] Downloading Haarcascade XML file...")
url = "https://github.com/opencv/opencv/raw/master/data/haarcascades/haarcascade_frontalface_default.xml"
urllib.request.urlretrieve(url, cascade_path)
print("[INFO] Download complete.")
def recognize_faces(self, video_source: int=0, width: int=640, height: int=480):
"""
Performs real-time face recognition using the webcam.
"""
cam = cv2.VideoCapture(video_source)
cam.set(3, width)
cam.set(4, height)
print("\n Starting face recognition. Look at the camera...")
while True:
ret, img = cam.read()
img = cv2.flip(img, -1)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = self.face_cascade.detectMultiScale(gray, 1.3, 5)
for (x, y, w, h) in faces:
cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), 2)
id, confidence = self.recognizer.predict(gray[y:y+h, x:x+w])
if confidence < 100:
name = self.names[id]
confidence_text = f" {round(100 - confidence)}%"
else:
name = "Unknown"
confidence_text = f" {round(100 - confidence)}%"
cv2.putText(img, name, (x+5, y-5), self.font, 1, (255, 255, 255), 2)
cv2.putText(img, confidence_text, (x+5, y+h-5), self.font, 1, (255, 255, 0), 1)
cv2.imshow('Face Recognition', img)
if cv2.waitKey(10) & 0xff == 27: # Press 'ESC' to exit
break
print("\n Exiting face recognition.")
cam.release()
cv2.destroyAllWindows()
# Usage Example
if __name__ == "__main__":
recognizer = FaceRecognizer(names=['None', 'John Doe', 'Jane Doe'])
recognizer.recognize_faces()
Conclusion
This tutorial has shown you how to build a modular, object-oriented face detection and recognition system using OpenCV. By organizing the code into classes, we’ve made it more maintainable, scalable, and easier to extend for future improvements or additional features.
Whether implementing a security system, developing a user authentication tool, or exploring computer vision, this approach lays a solid foundation. The code provided here can be adapted and enhanced to meet various needs and use cases.
Happy coding!