Python · Computer Vision

Using dlib in Python: The Complete Guide to Face Detection and Recognition

Face detection, 68-point facial landmarks, and 128-dimensional face recognition, explained with working code, real output, and a clear-eyed comparison against OpenCV and face_recognition.

By Arj Updated July 2026 22 min read Python 3

1What is dlib

dlib is a C++ toolkit with Python bindings, originally built for general-purpose machine learning but best known today for its computer vision work, particularly around faces. It covers a wide surface area: image processing, classic and deep machine learning, and facial analysis and biometric systems all live in the same library.

What makes dlib stand out for face-related work specifically is that it ships pretrained models, for detection, for 68-point landmarks, and for generating face embeddings, that are accurate enough to use in production without training anything yourself. This tutorial walks through all three, in the order you would actually use them in a real pipeline: detect the face, find its landmarks, then turn it into a numeric encoding you can compare against other faces.

Where this fits in your learning path
This guide assumes basic comfort with OpenCV for image loading and display. If you have not covered that yet, start with the OpenCV in Python guide first, since almost every dlib example here loads and displays images through cv2.

2Installing dlib

dlib's installation has more moving parts than most Python packages because it compiles C++ code under the hood, which means you need a working build toolchain before pip can succeed.

Step 1: install prerequisites

dlib's setup script uses CMake to drive the C++ build, so it has to be available first.

windows
pip install cmake
linux / macos
sudo apt install cmake

On macOS you will also need Xcode's command line tools if you have not already installed them (xcode-select --install), since CMake needs an actual C++ compiler to call.

Step 2: install dlib

terminal
pip install dlib

This compiles dlib from source the first time, which can take several minutes, this is normal and not a sign anything has gone wrong. You can check the package details on its PyPI page.

If the build fails on Windows
Windows is the most common place this install breaks, usually because Visual C++ Build Tools are missing. If pip install dlib fails after installing CMake, the most reliable fallback is a prebuilt wheel matching your exact Python version and architecture, for example a filename like dlib-19.24.0-cp39-cp39-win_amd64.whl, installed with pip install path/to/that_file.whl. Only use wheels from a source you trust, since installing a wheel runs its contents on your machine.

You will also want NumPy and OpenCV alongside dlib, since nearly every real dlib workflow loads images through OpenCV first:

terminal
pip install numpy opencv-python

3Detecting faces with dlib

dlib's built-in face detector uses a HOG (Histogram of Oriented Gradients) feature descriptor combined with a linear classifier, and it ships ready to use with no separate download required.

python
import dlib
import cv2

# Load detector
detector = dlib.get_frontal_face_detector()

# Load image and convert to grayscale
img = cv2.imread("person.jpg")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# Detect faces
faces = detector(gray)

for face in faces:
    x, y, w, h = face.left(), face.top(), face.width(), face.height()
    cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)

cv2.imshow("Face Detection", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
detector(image, upsample_num_times)

Calling detector(gray) returns a list of dlib.rectangle objects, one per detected face, each exposing .left(), .top(), .right(), and .bottom() (and the convenience methods .width() and .height() used above) to describe the bounding box.

The detector also accepts an optional second argument, the number of times to upsample the image before scanning. Passing detector(gray, 1) roughly doubles the image resolution internally before detecting, which helps catch smaller or more distant faces at the cost of noticeably slower processing.

Grayscale is not strictly required
Unlike some OpenCV workflows, dlib's detector will also accept a color image directly. Converting to grayscale first is still common because it is faster to process and matches how most tutorials and pretrained models were validated, but it is a performance choice rather than a hard requirement.

468-point facial landmark detection

Once you know where a face is, the next step is finding specific points on it, the corners of the eyes, the tip of the nose, the outline of the lips. dlib does this with a pretrained shape predictor model that locates 68 standardized points across the jawline, eyebrows, eyes, nose, and mouth.

This requires downloading the pretrained model file separately, since it is too large to ship inside the pip package itself. You can get it from the official dlib model files page, which you will need to decompress (it is a .bz2 archive) before use.

python
import dlib
import cv2

detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")

img = cv2.imread("face.jpg")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

faces = detector(gray)

for face in faces:
    landmarks = predictor(gray, face)
    for n in range(0, 68):
        x = landmarks.part(n).x
        y = landmarks.part(n).y
        cv2.circle(img, (x, y), 2, (255, 0, 0), -1)

cv2.imshow("Landmarks", img)
cv2.waitKey(0)
cv2.destroyAllWindows()

Notice the two-step pattern: the detector finds the face's bounding box first, and only then does predictor(gray, face) run inside that specific region to find the 68 points. The shape predictor does not scan the whole image on its own, it needs a face region to work within.

Point rangeFacial feature
0 to 16Jawline
17 to 26Eyebrows (left and right)
27 to 35Nose bridge and base
36 to 47Eyes (left and right)
48 to 67Outer and inner lips
Why landmarks matter beyond just drawing dots
These 68 coordinates are the foundation for a lot of downstream work: measuring eye aspect ratio to detect blinking or drowsiness, aligning a face to a standard orientation before recognition, or placing a virtual filter precisely over specific features. The points themselves are the building block, what you do with their positions is where the real applications live.

5Face embeddings for recognition

Detection tells you where a face is. Landmarks tell you its structure. Neither one tells you whose face it is, or whether two photos show the same person. That is what face embeddings solve: a pretrained neural network converts a face into a 128-dimensional vector of numbers, an encoding, positioned so that encodings of the same person's face sit close together in that 128-dimensional space, and encodings of different people sit far apart.

This model also has to be downloaded separately, available from the same dlib model files page:

python
face_rec_model_path = "dlib_face_recognition_resnet_model_v1.dat"

face_rec = dlib.face_recognition_model_v1(face_rec_model_path)

The full recognition pipeline

  1. Detect the face using dlib.get_frontal_face_detector(), exactly as in section 3.
  2. Get the landmarks using the shape_predictor, exactly as in section 4. The embedding model needs these landmarks to align the face consistently before encoding it.
  3. Compute the 128-dimensional encoding using face_recognition_model_v1, which turns the aligned face into the numeric vector used for comparison.
python
img = cv2.imread("person.jpg")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

faces = detector(gray)
for face in faces:
    landmarks = predictor(gray, face)
    encoding = face_rec.compute_face_descriptor(img, landmarks)
    print(list(encoding))  # this 128D vector can be used to compare faces
Note the switch back to the color image
compute_face_descriptor() is called with img, the original color image, not gray. The embedding model was trained on color input, so passing the grayscale version here would feed it the wrong kind of data even though detection and landmarks worked fine on grayscale.

6Comparing two faces

Once you have an encoding for two different face images, determining whether they show the same person becomes a simple distance calculation rather than anything vision-specific. Euclidean distance between the two 128-dimensional vectors is the standard metric:

python
from scipy.spatial import distance

dist = distance.euclidean(encoding1, encoding2)
if dist < 0.6:
    print("Same person")
else:
    print("Different people")
Where the 0.6 threshold comes from
This value is not arbitrary, it is the threshold dlib's own model was validated against during training, and it works well as a general default. That said, it is still a threshold, not a certainty. Lighting, angle, image quality, and age gaps between two photos of the same person can all shift the distance. For anything security-sensitive, test the threshold against your own dataset rather than trusting 0.6 blindly.

7Object detection with HOG and SVM

dlib's face detector is really a specific application of a more general technique: HOG features combined with a linear SVM (Support Vector Machine) classifier. The same underlying approach can be trained on custom objects, not just faces, using dlib.simple_object_detector_training_options() together with a set of images you have manually annotated with bounding boxes.

Training your own detector is a real undertaking: it needs a labeled dataset, careful tuning of the training options, and evaluation against held-out images. For the vast majority of face-related tasks, the pretrained models covered above are accurate enough that training your own is unnecessary. Custom training is worth reaching for mainly when you need to detect something dlib has no pretrained model for at all.

8dlib vs OpenCV vs face_recognition

These three tools overlap but are not interchangeable, and picking the right one depends on what you actually need to build.

FeaturedlibOpenCVface_recognition
Accuracy on face tasksHighLower, Haar Cascades struggle with angles and lightingHigh, built directly on dlib
SpeedSlowerFastSlower, same underlying models as dlib
Face embeddingsYes, 128DNoYes
Landmark detectionYes, 5 or 68 pointsLimited, fewer points and less accurateYes, via dlib
Ease of useMedium, more setup and more manual stepsEasy, simple APIVery easy, high-level wrapper around dlib
Custom model trainingYes, trainableLimitedNo training support
How to actually choose
Reach for OpenCV's Haar Cascades when you just need fast, rough face detection and accuracy is not critical, see the OpenCV in Python guide for that path. Reach for dlib directly when you need landmarks, embeddings, or the option to train custom detectors, and are comfortable with a slightly lower-level API. Reach for face_recognition when you want dlib's accuracy with the least code possible and do not need fine-grained control.

9Real-world use cases

  • Facial attendance systems, matching a live camera feed against a database of enrolled face encodings.
  • Biometric authentication, using face embeddings as one factor in a login or access control flow.
  • Virtual makeup or filters, using the 68 landmark points to precisely position overlays on lips, eyes, or cheeks.
  • Emotion detection, inferring expressions from the relative positions of landmark points, such as how far the mouth corners are raised.
  • Object tracking in surveillance, combining detection with a tracker to follow a face or object across video frames.

10Common errors and how to fix them

ErrorSolution
RuntimeError: Unable to open shape_predictor_68_face_landmarks.datDownload the model from the official dlib files page and make sure it is decompressed and the path in your code matches exactly
ModuleNotFoundError: No module named 'dlib'Install with pip install dlib, and confirm CMake is installed first if the build fails
Installation failure on WindowsInstall Visual C++ Build Tools, or fall back to a prebuilt .whl matching your Python version and system architecture
Detection or landmark extraction is very slowResize the image down before running detection, large images cost far more processing time than the accuracy gain is usually worth
No faces detected on an otherwise clear photoTry upsampling with detector(gray, 1), or confirm the face is reasonably front-facing, since HOG-based detection is weaker on extreme angles

11Performance tips

  • Resize before detecting. dlib's detection and landmark extraction both scale with pixel count, so running on a downscaled copy of a large photo, then mapping coordinates back up, is dramatically faster with minimal accuracy loss.
  • Avoid upsampling unless you need it. The optional upsample argument on the detector helps catch small faces, but it multiplies processing cost, only use it when detection is actually missing faces at the default setting.
  • Cache the models, do not reload them per frame. Loading the detector and shape predictor is comparatively expensive, load them once outside any video loop and reuse the same objects for every frame.
  • Batch or skip frames in video. As with any face pipeline, running full detection and encoding on every single frame is rarely necessary, detecting every few frames and tracking in between is usually visually indistinguishable and far cheaper.

12Where to go next

dlib offers everything from basic face detection to advanced facial embeddings and recognition in one toolkit. If you are building a secure, accurate, production-ready facial recognition system, it is a rock-solid foundation, and with the code in this guide you now have the full pipeline: detect faces, extract 68-point landmarks, generate 128-dimensional encodings, and compare faces using deep learning based recognition.

From here, a few natural directions to take it further:

  • Build a complete enrollment and matching system, storing known encodings and comparing new faces against the stored set, covered in the full face recognition system build.
  • Try the higher-level face_recognition library, which wraps everything in this guide into a simpler API when you do not need dlib's lower-level control.
  • Extend detection to live video using the patterns in the working with camera feed guide, combined with the performance tips above.

For the broader sequence of what to study before and after this topic, see the Python roadmap.

Keep building your Python skill tree
See exactly what to learn after dlib, in order, with every guide on this site mapped to a stage.
View the Python roadmap
Scroll to Top