1. Quick Start
face_recognition is the world's simplest Python library for recognizing and manipulating faces. Built on top of dlib's state-of-the-art deep learning models, it provides both a Python API and command-line tools for face detection, landmark identification, and face recognition with 99.38% accuracy on the Labeled Faces in the Wild benchmark.
Key features:
- Detect faces in images using HOG or CNN models
- Identify 68 facial landmarks (eyes, nose, mouth, chin, eyebrows)
- Generate 128-dimensional face encodings for comparison
- Compare faces with configurable tolerance thresholds
- Process images from files, webcams, or video streams
- Two CLI tools for scripted/batch workflows
- GPU acceleration via CUDA when dlib is compiled with CUDA support
- Multi-core parallel processing for batch image operations
Prerequisites: Python 3.5+ and a C++ compiler (for dlib)
Install:
pip install face_recognition
Minimal example:
import face_recognition
# Load images
known_image = face_recognition.load_image_file("known_person.jpg")
unknown_image = face_recognition.load_image_file("unknown_person.jpg")
# Encode faces
known_encoding = face_recognition.face_encodings(known_image)[0]
unknown_encoding = face_recognition.face_encodings(unknown_image)[0]
# Compare
results = face_recognition.compare_faces([known_encoding], unknown_encoding)
print(results)
[True]
Tip
For the fastest path to a working demo, use the
face_recognitionCLI tool — no Python code needed. See the Command-Line Tools section below.
What to try next:
- Use the CLI tools for quick face detection and recognition
- Explore facial landmarks for feature extraction
- Build a web service with the Flask example
- Set up real-time webcam recognition
2. Installation
System Requirements
| Requirement | Minimum | Recommended |
|---|---|---|
| Python | 3.5 | 3.8+ |
| OS | Linux, macOS, Windows | Ubuntu/Debian Linux |
| RAM | 2 GB | 4 GB+ |
| C++ Compiler | Required (for dlib) | gcc/g++ on Linux, Xcode on macOS |
| GPU (optional) | NVIDIA with CUDA | For CNN model and batch processing |
Install Methods
pip (recommended)
pip install face_recognition
Docker (CPU)
docker run -it --rm -v /path/to/images:/images ageitgey/face_recognition
Docker (GPU)
docker run -it --rm --runtime=nvidia -v /path/to/images:/images ageitgey/face_recognition:gpu
From source
git clone https://github.com/ageitgey/face_recognition.git
cd face_recognition
pip install -r requirements.txt
python setup.py install
Important
The
dlibdependency requires a C++ compiler. On Ubuntu/Debian, install build tools first:sudo apt-get install build-essential cmake. On macOS, install Xcode command-line tools:xcode-select --install. On Windows, install Visual Studio Build Tools with C++ workload.
Dependencies
| Package | Version | Purpose |
|---|---|---|
face_recognition_models |
>=0.3.0 | Pre-trained dlib model files (face detection, landmarks, encoding) |
dlib |
>=19.7 | Core C++ machine learning library |
Click |
>=6.0 | Command-line interface framework |
numpy |
any | Array operations for image data and encodings |
Pillow |
any | Image loading and format conversion |
scipy |
>=0.17.0 | Scientific computing (used in some examples) |
Post-Install Verification
face_detection --help
Usage: face_detection [OPTIONS] IMAGE_TO_CHECK
Options:
--cpus INTEGER number of CPU cores to use in parallel. -1 means "use
all in system"
--model TEXT Which face detection model to use. Options are "hog" or
"cnn".
--upsample INTEGER How many times to upsample the image looking for faces.
Higher numbers find smaller faces.
--help Show this message and exit.
python -c "import face_recognition; print(face_recognition.__version__)"
1.4.0
Install Troubleshooting
Error: Please install face_recognition_models
Cause: The face_recognition_models package was not installed or failed to install. This package contains the pre-trained model data files required by dlib.
Solution:
- Install the models package directly from GitHub:
pip install git+https://github.com/ageitgey/face_recognition_models - Verify installation:
python -c "import face_recognition_models; print('OK')"
Prevention: Always install via pip install face_recognition, which pulls in models as a dependency automatically.
Warning
Issues #1634 and #608 report this error frequently. If
pip install face_recognitiondoes not install the models package, install it manually from the GitHub URL above.
Error: RuntimeError: Unsupported image type, must be 8bit gray or RGB image
Cause: The image has an unsupported pixel format — typically a 32-bit RGBA PNG, a CMYK JPEG, or a 16-bit image. The dlib library only accepts 8-bit grayscale or 8-bit RGB images.
Solution:
- Convert the image to RGB before processing:
image = face_recognition.load_image_file("photo.png", mode='RGB') - The
load_image_file()function converts to RGB by default (mode='RGB'). If you're loading images manually with PIL or OpenCV, ensure you convert:from PIL import Image import numpy as np img = np.array(Image.open("photo.png").convert("RGB"))
Prevention: Always use face_recognition.load_image_file() instead of loading images manually. It handles format conversion automatically. Issues #1573, #1575, #21.
Error: dlib compilation fails
Cause: Missing C++ compiler or CMake.
Solution:
Ubuntu/Debian
sudo apt-get install build-essential cmake
pip install dlib
macOS
xcode-select --install
brew install cmake
pip install dlib
Windows
pip install cmake
pip install dlib
Prevention: Install build tools before attempting to install face_recognition.
Error: cv2.error: (-215:Assertion failed) !_src.empty() in function 'cv::cvtColor'
Cause: OpenCV received an empty frame from the video capture device. This happens when the webcam is not connected, is in use by another application, or the video file path is incorrect.
Solution:
- Check that the webcam is connected and not in use by another application
- Verify the video file path exists
- Add a frame check in your code:
ret, frame = video_capture.read() if not ret: print("Failed to capture frame") break
Prevention: Always check the return value of video_capture.read() before processing the frame. Issue #933.
Error: pkg_resources deprecation warning
Cause: The pkg_resources package (used internally by face_recognition_models) is scheduled for removal. Issue #1653.
Solution:
pip install setuptools
Prevention: Keep setuptools installed and up to date.
3. Core Usage
Loading Images
Every workflow starts with loading an image into a numpy array:
import face_recognition
image = face_recognition.load_image_file("photo.jpg")
The load_image_file() function accepts file paths or file-like objects and returns a numpy array.
| Parameter | Type | Default | Description |
|---|---|---|---|
file |
str or file object | — | Image file path or file object |
mode |
str | 'RGB' |
Color mode: 'RGB' (3-channel color) or 'L' (grayscale) |
# Load as grayscale
gray_image = face_recognition.load_image_file("photo.jpg", mode='L')
# Load from file object
with open("photo.jpg", "rb") as f:
image = face_recognition.load_image_file(f)
Note
Supported image formats include JPEG, PNG, BMP, GIF, and any other format supported by Pillow. 32-bit images are automatically converted to 8-bit RGB when using the default
mode='RGB'.
Detecting Faces
Locate all faces in an image and get their bounding box coordinates:
image = face_recognition.load_image_file("group_photo.jpg")
face_locations = face_recognition.face_locations(image)
for top, right, bottom, left in face_locations:
print(f"Face found at: Top={top}, Right={right}, Bottom={bottom}, Left={left}")
Face found at: Top=142, Right=617, Bottom=409, Left=349
| Parameter | Type | Default | Description |
|---|---|---|---|
img |
numpy array | — | The image to search |
number_of_times_to_upsample |
int | 1 |
How many times to upsample the image. Higher values find smaller faces but are slower. |
model |
str | "hog" |
Detection model: "hog" (faster, CPU) or "cnn" (more accurate, GPU-accelerated) |
Face locations are returned as tuples in (top, right, bottom, left) order.
# Use CNN model for higher accuracy (requires GPU for reasonable speed)
face_locations = face_recognition.face_locations(image, model="cnn")
# Find smaller faces by upsampling
face_locations = face_recognition.face_locations(image, number_of_times_to_upsample=2)
Tip
The HOG model is the right choice for most use cases — it runs well on CPU and is fast enough for real-time webcam processing. Use CNN only if you need higher accuracy and have a CUDA-capable GPU.
Batch Face Detection (GPU)
Process multiple images in a single GPU batch for significantly faster throughput:
images = [face_recognition.load_image_file(f) for f in ["img1.jpg", "img2.jpg", "img3.jpg"]]
batch_locations = face_recognition.batch_face_locations(images, number_of_times_to_upsample=0)
for i, face_locations in enumerate(batch_locations):
print(f"Image {i}: found {len(face_locations)} face(s)")
| Parameter | Type | Default | Description |
|---|---|---|---|
images |
list of numpy arrays | — | List of images to process |
number_of_times_to_upsample |
int | 1 |
Upsample count for face detection |
batch_size |
int | 128 |
Number of images per GPU batch |
Important
batch_face_locations()always uses the CNN model internally. It only provides a speed benefit when using a CUDA-capable GPU. On CPU-only systems, useface_locations()in a loop instead.
Finding Facial Landmarks
Identify facial features (eyes, nose, mouth, chin, eyebrows) for each detected face:
image = face_recognition.load_image_file("photo.jpg")
landmarks_list = face_recognition.face_landmarks(image)
for face_landmarks in landmarks_list:
for feature_name, points in face_landmarks.items():
print(f"{feature_name}: {len(points)} points")
chin: 17 points
left_eyebrow: 5 points
right_eyebrow: 5 points
nose_bridge: 4 points
nose_tip: 5 points
left_eye: 6 points
right_eye: 6 points
top_lip: 12 points
bottom_lip: 12 points
| Parameter | Type | Default | Description |
|---|---|---|---|
face_image |
numpy array | — | The image to search |
face_locations |
list or None | None |
Pre-computed face locations (skips detection if provided) |
model |
str | "large" |
Landmark model: "large" (68 points, 9 features) or "small" (5 points, 3 features) |
Large model features (68 landmarks):
| Feature | Points |
|---|---|
chin |
17 |
left_eyebrow |
5 |
right_eyebrow |
5 |
nose_bridge |
4 |
nose_tip |
5 |
left_eye |
6 |
right_eye |
6 |
top_lip |
12 |
bottom_lip |
12 |
Small model features (5 landmarks):
| Feature | Points |
|---|---|
nose_tip |
1 |
left_eye |
2 |
right_eye |
2 |
Warning
Passing an invalid model name (anything other than
"large"or"small") raisesValueError: Invalid landmarks model type. Supported models are ['small', 'large'].
Encoding Faces
Generate a 128-dimensional encoding vector for each face, used for comparison:
image = face_recognition.load_image_file("person.jpg")
encodings = face_recognition.face_encodings(image)
print(f"Found {len(encodings)} face(s)")
print(f"Encoding dimensions: {len(encodings[0])}")
Found 1 face(s)
Encoding dimensions: 128
| Parameter | Type | Default | Description |
|---|---|---|---|
face_image |
numpy array | — | Image containing faces |
known_face_locations |
list or None | None |
Pre-computed face locations (skips detection if provided) |
num_jitters |
int | 1 |
Times to re-sample each face for encoding. Higher is more accurate but slower (100 = 100x slower). |
model |
str | "small" |
Landmark model used internally: "large" or "small" |
# Higher accuracy encoding (slower)
encodings = face_recognition.face_encodings(image, num_jitters=10)
# Skip face detection by providing known locations
locations = face_recognition.face_locations(image)
encodings = face_recognition.face_encodings(image, known_face_locations=locations)
Comparing Faces
Check if faces match by comparing their encodings:
known_image = face_recognition.load_image_file("known_person.jpg")
unknown_image = face_recognition.load_image_file("unknown_person.jpg")
known_encoding = face_recognition.face_encodings(known_image)[0]
unknown_encoding = face_recognition.face_encodings(unknown_image)[0]
results = face_recognition.compare_faces([known_encoding], unknown_encoding)
print(f"Match: {results[0]}")
Match: True
| Parameter | Type | Default | Description |
|---|---|---|---|
known_face_encodings |
list | — | List of known face encodings to compare against |
face_encoding_to_check |
numpy array | — | The face encoding to check |
tolerance |
float | 0.6 |
Distance threshold for a match. Lower is stricter. |
Measuring Face Distance
Get the euclidean distance between face encodings for fine-grained similarity:
distances = face_recognition.face_distance(known_encodings, unknown_encoding)
for i, distance in enumerate(distances):
print(f"Distance to person {i}: {distance:.4f}")
print(f" Match at 0.6 threshold: {distance <= 0.6}")
print(f" Match at 0.5 threshold: {distance <= 0.5}")
Distance to person 0: 0.3142
Match at 0.6 threshold: True
Match at 0.5 threshold: True
Distance to person 1: 0.7856
Match at 0.6 threshold: False
Match at 0.5 threshold: False
| Parameter | Type | Default | Description |
|---|---|---|---|
face_encodings |
list | — | List of face encodings to compare |
face_to_compare |
numpy array | — | The face encoding to measure against |
Tip
The default tolerance of
0.6works well for most cases. Lower it to0.5to reduce false positives at the cost of more false negatives. Useface_distance()to find the optimal threshold for your dataset.
Command-Line Tools
Two CLI commands are installed with the package:
face_recognition — Identify Faces
Compares faces in images against a folder of known people:
face_recognition ./known_people/ ./unknown_pictures/
unknown_pictures/photo1.jpg,Barack Obama
unknown_pictures/photo2.jpg,unknown_person
unknown_pictures/photo3.jpg,Joe Biden
The known people folder should contain one image per person, with the filename as the person's name (e.g., Barack_Obama.jpg).
| Argument/Option | Default | Description |
|---|---|---|
known_people_folder |
— | Directory of known face images (filename = person name) |
image_to_check |
— | Image file or directory to check |
--cpus |
1 |
CPU cores for parallel processing. -1 = all cores. |
--tolerance |
0.6 |
Match tolerance. Lower = stricter. |
--show-distance |
False |
Include face distance in output. |
# Process a folder with all CPU cores
face_recognition --cpus -1 ./known_people/ ./photo_folder/
# Stricter matching with distance output
face_recognition --tolerance 0.5 --show-distance 1 ./known_people/ ./test.jpg
test.jpg,Barack Obama,0.3142
Note
Images larger than 1600px on either dimension are automatically scaled down to 1600x1600 for faster processing. Recognition still works on the scaled image.
face_detection — Locate Faces
Finds faces in images and outputs bounding box coordinates:
face_detection ./photo.jpg
photo.jpg,142,617,409,349
Output format: filename,top,right,bottom,left
| Argument/Option | Default | Description |
|---|---|---|
image_to_check |
— | Image file or directory to scan |
--cpus |
1 |
CPU cores for parallel processing. -1 = all cores. |
--model |
"hog" |
Detection model: "hog" or "cnn" |
--upsample |
0 |
Times to upsample for smaller face detection |
# Use CNN model for higher accuracy
face_detection --model cnn ./photos/
# Find small faces with upsampling
face_detection --upsample 2 ./group_photo.jpg
4. Common Tasks
Recognize Faces in a Webcam Stream
import face_recognition
import cv2
import numpy as np
# Load known faces
known_image = face_recognition.load_image_file("known_person.jpg")
known_encoding = face_recognition.face_encodings(known_image)[0]
known_names = ["Known Person"]
known_encodings = [known_encoding]
video_capture = cv2.VideoCapture(0)
while True:
ret, frame = video_capture.read()
if not ret:
break
rgb_frame = frame[:, :, ::-1]
face_locations = face_recognition.face_locations(rgb_frame)
face_encodings = face_recognition.face_encodings(rgb_frame, face_locations)
for (top, right, bottom, left), face_encoding in zip(face_locations, face_encodings):
matches = face_recognition.compare_faces(known_encodings, face_encoding)
name = "Unknown"
face_distances = face_recognition.face_distance(known_encodings, face_encoding)
best_match_index = np.argmin(face_distances)
if matches[best_match_index]:
name = known_names[best_match_index]
cv2.rectangle(frame, (left, top), (right, bottom), (0, 0, 255), 2)
cv2.rectangle(frame, (left, bottom - 35), (right, bottom), (0, 0, 255), cv2.FILLED)
cv2.putText(frame, name, (left + 6, bottom - 6), cv2.FONT_HERSHEY_DUPLEX, 1.0, (255, 255, 255), 1)
cv2.imshow('Video', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
video_capture.release()
cv2.destroyAllWindows()
Tip
For better performance, process every other frame and resize to 1/4 size:
small_frame = cv2.resize(frame, (0, 0), fx=0.25, fy=0.25). Scale face coordinates back up by 4x for display.
Faster Webcam Recognition
Process at 1/4 resolution and skip every other frame:
import face_recognition
import cv2
import numpy as np
video_capture = cv2.VideoCapture(0)
# Load known faces
known_image = face_recognition.load_image_file("known_person.jpg")
known_encoding = face_recognition.face_encodings(known_image)[0]
known_encodings = [known_encoding]
known_names = ["Known Person"]
face_locations = []
face_names = []
process_this_frame = True
while True:
ret, frame = video_capture.read()
if not ret:
break
if process_this_frame:
small_frame = cv2.resize(frame, (0, 0), fx=0.25, fy=0.25)
rgb_small_frame = small_frame[:, :, ::-1]
face_locations = face_recognition.face_locations(rgb_small_frame)
face_encodings_list = face_recognition.face_encodings(rgb_small_frame, face_locations)
face_names = []
for encoding in face_encodings_list:
matches = face_recognition.compare_faces(known_encodings, encoding)
name = "Unknown"
distances = face_recognition.face_distance(known_encodings, encoding)
best_idx = np.argmin(distances)
if matches[best_idx]:
name = known_names[best_idx]
face_names.append(name)
process_this_frame = not process_this_frame
for (top, right, bottom, left), name in zip(face_locations, face_names):
top *= 4; right *= 4; bottom *= 4; left *= 4
cv2.rectangle(frame, (left, top), (right, bottom), (0, 0, 255), 2)
cv2.rectangle(frame, (left, bottom - 35), (right, bottom), (0, 0, 255), cv2.FILLED)
cv2.putText(frame, name, (left + 6, bottom - 6), cv2.FONT_HERSHEY_DUPLEX, 1.0, (255, 255, 255), 1)
cv2.imshow('Video', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
video_capture.release()
cv2.destroyAllWindows()
Recognize Faces in a Video File
import face_recognition
import cv2
input_movie = cv2.VideoCapture("input_video.mp4")
length = int(input_movie.get(cv2.CAP_PROP_FRAME_COUNT))
fourcc = cv2.VideoWriter_fourcc(*'XVID')
output_movie = cv2.VideoWriter('output.avi', fourcc, 29.97, (640, 360))
# Load known faces
known_image = face_recognition.load_image_file("known_person.png")
known_encoding = face_recognition.face_encodings(known_image)[0]
frame_number = 0
while True:
ret, frame = input_movie.read()
if not ret:
break
frame_number += 1
rgb_frame = frame[:, :, ::-1]
face_locations = face_recognition.face_locations(rgb_frame)
face_encodings_list = face_recognition.face_encodings(rgb_frame, face_locations)
for (top, right, bottom, left), encoding in zip(face_locations, face_encodings_list):
match = face_recognition.compare_faces([known_encoding], encoding, tolerance=0.50)
if match[0]:
cv2.rectangle(frame, (left, top), (right, bottom), (0, 0, 255), 2)
cv2.rectangle(frame, (left, bottom - 25), (right, bottom), (0, 0, 255), cv2.FILLED)
cv2.putText(frame, "Known Person", (left + 6, bottom - 6),
cv2.FONT_HERSHEY_DUPLEX, 0.5, (255, 255, 255), 1)
print(f"Writing frame {frame_number} / {length}")
output_movie.write(frame)
input_movie.release()
cv2.destroyAllWindows()
Apply Digital Makeup
Use facial landmarks to draw on facial features:
from PIL import Image, ImageDraw
import face_recognition
image = face_recognition.load_image_file("photo.jpg")
face_landmarks_list = face_recognition.face_landmarks(image)
pil_image = Image.fromarray(image)
for face_landmarks in face_landmarks_list:
d = ImageDraw.Draw(pil_image, 'RGBA')
# Eyebrows
d.polygon(face_landmarks['left_eyebrow'], fill=(68, 54, 39, 128))
d.polygon(face_landmarks['right_eyebrow'], fill=(68, 54, 39, 128))
# Lips
d.polygon(face_landmarks['top_lip'], fill=(150, 0, 0, 128))
d.polygon(face_landmarks['bottom_lip'], fill=(150, 0, 0, 128))
# Eyes
d.polygon(face_landmarks['left_eye'], fill=(255, 255, 255, 30))
d.polygon(face_landmarks['right_eye'], fill=(255, 255, 255, 30))
# Eyeliner
d.line(face_landmarks['left_eye'] + [face_landmarks['left_eye'][0]],
fill=(0, 0, 0, 110), width=6)
d.line(face_landmarks['right_eye'] + [face_landmarks['right_eye'][0]],
fill=(0, 0, 0, 110), width=6)
pil_image.show()
Blur Faces in a Webcam Stream
import face_recognition
import cv2
video_capture = cv2.VideoCapture(0)
while True:
ret, frame = video_capture.read()
if not ret:
break
small_frame = cv2.resize(frame, (0, 0), fx=0.25, fy=0.25)
face_locations = face_recognition.face_locations(small_frame, model="cnn")
for top, right, bottom, left in face_locations:
top *= 4; right *= 4; bottom *= 4; left *= 4
face_image = frame[top:bottom, left:right]
face_image = cv2.GaussianBlur(face_image, (99, 99), 30)
frame[top:bottom, left:right] = face_image
cv2.imshow('Video', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
video_capture.release()
cv2.destroyAllWindows()
Build a KNN Face Classifier
For recognizing a large set of known people, train a k-nearest neighbors model:
import face_recognition
from face_recognition.face_recognition_cli import image_files_in_folder
from sklearn import neighbors
import os
import math
import pickle
def train(train_dir, model_save_path=None, n_neighbors=None, knn_algo='ball_tree'):
X = []
y = []
for class_dir in os.listdir(train_dir):
if not os.path.isdir(os.path.join(train_dir, class_dir)):
continue
for img_path in image_files_in_folder(os.path.join(train_dir, class_dir)):
image = face_recognition.load_image_file(img_path)
face_bounding_boxes = face_recognition.face_locations(image)
if len(face_bounding_boxes) == 1:
X.append(face_recognition.face_encodings(
image, known_face_locations=face_bounding_boxes)[0])
y.append(class_dir)
if n_neighbors is None:
n_neighbors = int(round(math.sqrt(len(X))))
knn_clf = neighbors.KNeighborsClassifier(
n_neighbors=n_neighbors, algorithm=knn_algo, weights='distance')
knn_clf.fit(X, y)
if model_save_path is not None:
with open(model_save_path, 'wb') as f:
pickle.dump(knn_clf, f)
return knn_clf
Important
The KNN example requires scikit-learn:
pip install scikit-learn. Organize training images astrain_dir/person_name/image.jpg— one subdirectory per person, each containing one or more face images of that person. Each training image must contain exactly one face.
Training directory structure:
train_dir/
├── person_1/
│ ├── img1.jpg
│ ├── img2.jpg
├── person_2/
│ ├── img1.jpg
│ └── img2.jpg
└── ...
Build a Face Recognition Web Service
import face_recognition
from flask import Flask, jsonify, request, redirect
ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif'}
app = Flask(__name__)
def allowed_file(filename):
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
@app.route('/', methods=['GET', 'POST'])
def upload_image():
if request.method == 'POST':
if 'file' not in request.files:
return redirect(request.url)
file = request.files['file']
if file.filename == '':
return redirect(request.url)
if file and allowed_file(file.filename):
return detect_faces_in_image(file)
return '''
<!doctype html>
<title>Face Recognition</title>
<h1>Upload a picture to check for faces</h1>
<form method="POST" enctype="multipart/form-data">
<input type="file" name="file">
<input type="submit" value="Upload">
</form>
'''
def detect_faces_in_image(file_stream):
img = face_recognition.load_image_file(file_stream)
encodings = face_recognition.face_encodings(img)
result = {"face_found_in_image": len(encodings) > 0, "face_count": len(encodings)}
return jsonify(result)
if __name__ == "__main__":
app.run(host='0.0.0.0', port=5001, debug=True)
Note
This requires Flask:
pip install flask. Test with:curl -XPOST -F "file=@photo.jpg" http://127.0.0.1:5001
Detect Eye Blinks
Use the eye aspect ratio (EAR) algorithm with facial landmarks:
import face_recognition
import cv2
from scipy.spatial import distance as dist
def get_ear(eye):
A = dist.euclidean(eye[1], eye[5])
B = dist.euclidean(eye[2], eye[4])
C = dist.euclidean(eye[0], eye[3])
return (A + B) / (2.0 * C)
video_capture = cv2.VideoCapture(0)
while True:
ret, frame = video_capture.read()
if not ret:
break
small_frame = cv2.resize(frame, (0, 0), fx=0.25, fy=0.25)
rgb_small_frame = small_frame[:, :, ::-1]
face_landmarks_list = face_recognition.face_landmarks(rgb_small_frame)
for face_landmarks in face_landmarks_list:
left_ear = get_ear(face_landmarks['left_eye'])
right_ear = get_ear(face_landmarks['right_eye'])
if left_ear < 0.2 and right_ear < 0.2:
print("EYES CLOSED")
else:
print("EYES OPEN")
if cv2.waitKey(1) & 0xFF == ord('q'):
break
video_capture.release()
cv2.destroyAllWindows()
Run on a Raspberry Pi
import face_recognition
import picamera
import numpy as np
camera = picamera.PiCamera()
camera.resolution = (320, 240)
output = np.empty((240, 320, 3), dtype=np.uint8)
# Load a known face
known_image = face_recognition.load_image_file("known_person.jpg")
known_encoding = face_recognition.face_encodings(known_image)[0]
while True:
camera.capture(output, format="rgb")
face_locations = face_recognition.face_locations(output)
face_encodings_list = face_recognition.face_encodings(output, face_locations)
for face_encoding in face_encodings_list:
match = face_recognition.compare_faces([known_encoding], face_encoding)
if match[0]:
print("Known person detected!")
else:
print("Unknown person")
Warning
Raspberry Pi requires
picamera[array]module and camera enabled viaraspi-config. Use a low resolution (320x240) for acceptable performance on RPi 2+.
5. Troubleshooting
Diagnostic Decision Tree
Problem?
├── Import error → Check dlib and face_recognition_models are installed
├── No faces found → Try upsampling, check image format, try CNN model
├── Wrong matches → Lower tolerance (try 0.5 or 0.4)
├── Too slow → Use HOG model, reduce image size, process fewer frames
├── Webcam not working → Check cv2.VideoCapture(0) returns frames
└── CUDA errors → Verify dlib was compiled with CUDA support
Error: ValueError: Invalid landmarks model type
Cause: An invalid model name was passed to face_landmarks(). Only "large" and "small" are supported.
Solution:
# Correct usage
landmarks = face_recognition.face_landmarks(image, model="large") # 68 points
landmarks = face_recognition.face_landmarks(image, model="small") # 5 points
Prevention: Only use "large" or "small" as the model parameter.
Error: RuntimeError: Error while calling cudaOccupancyMaxPotentialBlockSize
Cause: CUDA driver or runtime version mismatch, or insufficient GPU memory. Issue #1641.
Solution:
- Verify CUDA installation:
nvidia-smi - Ensure dlib was compiled with CUDA:
python -c "import dlib; print(dlib.DLIB_USE_CUDA)" - If CUDA is not available, fall back to HOG model:
face_locations = face_recognition.face_locations(image, model="hog")
Prevention: Match CUDA toolkit version with your GPU driver version. Use HOG model if GPU is unreliable.
Error: compute_face_descriptor(): incompatible function arguments
Cause: Image data is in the wrong format — typically a PIL Image object was passed instead of a numpy array, or the array has the wrong dtype. Issue #1582.
Solution:
# Always use load_image_file() or convert properly
image = face_recognition.load_image_file("photo.jpg")
# OR
import numpy as np
from PIL import Image
image = np.array(Image.open("photo.jpg").convert("RGB"))
Prevention: Use face_recognition.load_image_file() for all image loading.
Multiprocessing output is interleaved
Cause: When using --cpus greater than 1, worker processes write to stdout concurrently, which can produce jumbled output. Issue #1665.
Solution: Post-process the output by sorting lines by filename:
face_recognition --cpus -1 ./known/ ./test/ | sort
Prevention: Use --cpus 1 if output ordering matters, or redirect to a file and sort afterward.
No faces detected in an image
Cause: Faces may be too small, the image may be low quality, or faces may be at extreme angles.
Solution:
- Increase upsampling:
face_locations = face_recognition.face_locations(image, number_of_times_to_upsample=2) - Try the CNN model for better accuracy:
face_locations = face_recognition.face_locations(image, model="cnn") - Ensure the image is in RGB format (not BGR from OpenCV):
rgb_image = cv2_image[:, :, ::-1]
Prevention: Use the CNN model and higher upsampling for challenging images.
Caution
Face detection accuracy degrades significantly with very small faces (below ~80px), extreme head rotation (profile views), heavy occlusion, or very low-resolution images. There is no workaround for these physical limitations of the model.
Inaccurate photo recognition
Cause: The default tolerance of 0.6 may be too permissive for your dataset, leading to false positives. Issue #1647.
Solution:
- Lower the tolerance:
results = face_recognition.compare_faces(known_encodings, unknown_encoding, tolerance=0.5) - Use
face_distance()to understand the distribution of distances in your dataset and select an appropriate threshold - Use multiple training images per person for better encoding stability
Prevention: Test with --show-distance to calibrate the tolerance for your specific use case.
6. FAQ
Q: What is the accuracy of the face recognition?
The underlying model achieves 99.38% accuracy on the Labeled Faces in the Wild benchmark. Real-world accuracy depends on image quality, lighting, and face angles. The default tolerance of 0.6 balances false positives against false negatives.
Q: What is the difference between HOG and CNN face detection models?
HOG (Histogram of Oriented Gradients) is faster and works well on CPU. CNN (Convolutional Neural Network) is more accurate but significantly slower without GPU acceleration. HOG is the default and recommended for most use cases. Use CNN when you need higher accuracy and have a CUDA-capable GPU.
Q: How do I improve recognition accuracy?
Lower the tolerance (e.g., 0.5 instead of the default 0.6) to reduce false positives. Use num_jitters greater than 1 when computing encodings for more stable results. Provide multiple training images per person when building a classifier. Ensure images are well-lit and faces are reasonably frontal.
Q: Does face_recognition work with video files?
Yes. Use OpenCV (cv2) to read video frames, convert each frame from BGR to RGB (frame[:, :, ::-1]), and pass it to any face_recognition function. See the "Recognize Faces in a Video File" recipe above.
Q: Can I use a GPU for face detection?
Yes. Install dlib with CUDA support (requires NVIDIA GPU, CUDA toolkit, and cuDNN). Then use model="cnn" for face_locations() or use batch_face_locations() for GPU-batched processing.
Q: What image formats are supported?
Any format supported by Pillow, including JPEG, PNG, BMP, GIF, TIFF, and WebP. The load_image_file() function handles format conversion automatically.
Q: How do I handle images with no faces?
face_locations() returns an empty list [] if no faces are found. face_encodings() also returns an empty list. Always check the length before indexing:
encodings = face_recognition.face_encodings(image)
if len(encodings) > 0:
encoding = encodings[0]
else:
print("No faces found")
Q: What is the face encoding format?
Each face encoding is a 128-dimensional numpy array of float values. Encodings can be serialized with pickle or numpy.save() for storage. The euclidean distance between two encodings indicates how similar the faces are — distances below 0.6 typically indicate the same person.
Q: Can I use face_recognition on a Raspberry Pi?
Yes, on Raspberry Pi 2 or later. Install with pip install face_recognition (compilation will take a long time). Use low resolutions (320x240) and the picamera module for camera input. Performance will be slower than desktop systems.
Q: Does it work with OpenCV images?
Yes, but OpenCV uses BGR color order while face_recognition expects RGB. Convert with: rgb_image = cv2_image[:, :, ::-1]
For full architecture details, deployment options, and configuration reference, see the Admin Guide.