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.
- 1What is dlib
- 2Installing dlib
- 3Detecting faces with dlib
- 468-point facial landmark detection
- 5Face embeddings for recognition
- 6Comparing two faces
- 7Object detection with HOG and SVM
- 8dlib vs OpenCV vs face_recognition
- 9Real-world use cases
- 10Common errors and how to fix them
- 11Performance tips
- 12Where to go next
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.
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.
pip install cmake
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
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.
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:
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.
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()
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.
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.
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 range | Facial feature |
|---|---|
| 0 to 16 | Jawline |
| 17 to 26 | Eyebrows (left and right) |
| 27 to 35 | Nose bridge and base |
| 36 to 47 | Eyes (left and right) |
| 48 to 67 | Outer and inner lips |
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:
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
- Detect the face using
dlib.get_frontal_face_detector(), exactly as in section 3. - 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. - Compute the 128-dimensional encoding using
face_recognition_model_v1, which turns the aligned face into the numeric vector used for comparison.
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
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:
from scipy.spatial import distance dist = distance.euclidean(encoding1, encoding2) if dist < 0.6: print("Same person") else: print("Different people")
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.
| Feature | dlib | OpenCV | face_recognition |
|---|---|---|---|
| Accuracy on face tasks | High | Lower, Haar Cascades struggle with angles and lighting | High, built directly on dlib |
| Speed | Slower | Fast | Slower, same underlying models as dlib |
| Face embeddings | Yes, 128D | No | Yes |
| Landmark detection | Yes, 5 or 68 points | Limited, fewer points and less accurate | Yes, via dlib |
| Ease of use | Medium, more setup and more manual steps | Easy, simple API | Very easy, high-level wrapper around dlib |
| Custom model training | Yes, trainable | Limited | No training support |
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
| Error | Solution |
|---|---|
RuntimeError: Unable to open shape_predictor_68_face_landmarks.dat | Download 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 Windows | Install Visual C++ Build Tools, or fall back to a prebuilt .whl matching your Python version and system architecture |
| Detection or landmark extraction is very slow | Resize 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 photo | Try 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.
