Library / SDK
1adrianb/face-alignment avatar
1adrianb/face-alignment

1adrianb/face-alignment: 2D and 3D facial landmarks in Python

:fire: 2D and 3D Face alignment library build using pytorch

7,537 stars1,383 forksPythonBSD-3-Clause

At a glance

What is it?
The face-alignment package wraps a FAN network behind a small Python API that returns 68-point 2D or 3D landmarks, with five swappable face detectors and an optional ONNX path. It is a research-grade library, not a product, and the README says so.
Who is it for?
Adopt face-alignment when you need 68-point 2D or 3D landmarks inside a Python or PyTorch pipeline and you are willing to pin a PyTorch version and accept a first-run torch.compile cost of roughly 25 seconds. Do not adopt it if you need a documented numerical evaluation harness: the README points to the separate Lua implementation for that, because the Python models are not the ones evaluated in the paper.
Can I use it commercially?
Yes. BSD-3-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 176 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 17, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What face-alignment actually returns, and who needs it

The package predicts facial landmark coordinates from an image. The README frames it as a wrapper around FAN, the face alignment network from the 2017 ICCV paper by Bulat and Tzimiropoulos, and exposes two output modes: TWO_D and THREE_D. A single call, get_landmarks, takes an image array and returns predictions; there is also get_landmarks_from_directory for batch processing a folder of images in one go.

The audience is narrow and specific. This is for engineers building a face pipeline in Python who need point coordinates rather than a face crop or an identity embedding. Typical uses are fitting a 3D morphable model, driving an avatar rig, measuring inter-ocular distance, or preprocessing before a recognition stage. If you only need bounding boxes, the landmark network is wasted work and a plain detector is the better choice. The README also notes a Lua version exists for numerical evaluations, which is a strong hint about where the Python package sits: convenience and integration, not paper reproduction.

The detection and alignment pipeline, and why the detector choice dominates

The flow is two stages. A face detector proposes bounding boxes, then the landmark network regresses points inside each box. The README states that SFD is the default detector and the most accurate, but also the slowest, and that the library supports several backends selected with the face_detector argument.

The published timings are detection-only medians over 20 runs on a single 450x450 face on an Apple M2. SFD sits at 138.8 ms on CPU and 33.1 ms on MPS. BlazeFace is 10.9 ms on CPU and 8.2 ms on MPS. YuNet is 5.6 ms on CPU with no MPS figure, RetinaFace is 25.2 ms on CPU and 15.5 ms on MPS, and SCRFD is 23.1 ms on CPU with no MPS figure. Those numbers are for detection alone, so they do not tell you the end-to-end cost of a landmark prediction.

The device support column is the part that decides real deployments. SFD, BlazeFace and RetinaFace run on CPU, CUDA and MPS. YuNet runs through OpenCV DNN and is CPU only. SCRFD runs through ONNX Runtime and is also CPU only, and it needs the optional onnxruntime package. dlib is listed as deprecated and has no timing entry. If you are targeting Apple silicon and want the fastest path, BlazeFace is the only sub-10 ms option with MPS support in the table.

Installing face-alignment and running a first prediction

The README gives pip as the easiest route. Python 3.9 or newer is required, along with PyTorch 2.0 or newer, and Linux, Windows or macOS are all listed as supported. A CUDA GPU is described as highly recommended for detector performance, though not required.

bash
pip install face-alignment

After that, the minimal 2D example from the README is four lines of setup plus a prediction call. The flip_input flag is passed as False in every README example, and the LandmarksType enum selects the output dimensionality.

python
import face_alignment
from skimage import io

fa = face_alignment.FaceAlignment(face_alignment.LandmarksType.TWO_D, flip_input=False)

input = io.imread('../test/assets/aflw-test.jpg')
preds = fa.get_landmarks(input)

The first run will not be instant. The README states the landmark network is compiled with torch.compile by default and that compilation artifacts are cached to disk, so only the first run is slow, at roughly 25 seconds. If that startup cost is unacceptable, pass compile=False, which the README describes as skipping compilation for instant startup.

python
import face_alignment

fa = face_alignment.FaceAlignment(face_alignment.LandmarksType.TWO_D, device='cpu', compile=False)

To run on a GPU, pass device='cuda' for CUDA or device='mps' for Apple M GPUs, and dtype=torch.bfloat16 is shown alongside it. For multi-face images on a low-memory GPU, max_batch_size defaults to 1 and can be raised. The repository also ships examples/detect_landmarks_in_image.py and examples/demo.ipynb if you prefer a runnable script over the README snippets.

Skipping detection entirely with ground truth boxes

One option in the README is easy to miss and useful for evaluation work. Passing face_detector='folder' skips detection and loads pre-computed bounding boxes from .npy, .t7 or .pth files that match each image filename. The README describes this as useful for evaluation with ground truth boxes.

python
import face_alignment

fa = face_alignment.FaceAlignment(face_alignment.LandmarksType.TWO_D, face_detector='folder')

This matters because it removes the detector from the error budget. If your landmark results look wrong, running with folder boxes tells you whether the problem is the alignment network or the detection stage. The constraint is the filename convention: the box file must match the image filename, and the README does not spell out the exact matching rule beyond that. You will be reading the source to confirm it.

Where face-alignment is the wrong tool

The README is unusually candid about one limitation: for numerical evaluations it recommends the Lua version, which uses models identical to the ones evaluated in the paper. The Python package does not carry that guarantee. If your goal is to reproduce published benchmark numbers, this is the wrong implementation.

The second limitation is platform coverage in the detector table. YuNet and SCRFD have no MPS timing and are described as CPU only, so an Apple silicon deployment that wants either of those backends is out of luck. SCRFD additionally requires installing onnxruntime separately, which setup.py exposes as the scrfd extra rather than a default dependency.

The third is the documentation boundary. The README says the work is presented as a black-box and directs readers to the original paper for the internals. There is no description of the network architecture, the training data beyond the paper citation, or the failure conditions. There is also no documented rollback or model-version pinning story, and no accuracy table per detector, so detector choice has to be validated on your own images rather than selected from published numbers.

Finally, torch.compile being on by default is a trade-off, not a free win. The README quantifies the first-run cost at roughly 25 seconds and notes the artifacts are cached, but a container that starts cold on every request pays that cost unless the cache directory is persisted.

How it compares to dlib and to MediaPipe-style detector stacks

The closest comparison inside this repository is dlib, which the README lists as a supported but deprecated detector backend. dlib's landmark predictor is a classical regression-tree approach that runs on CPU without a PyTorch dependency; here it is only one interchangeable front end feeding the same FAN network, and it carries no timing entry in the table. Choosing dlib through this package gets you the FAN landmarks, not dlib's own predictor.

Against a general-purpose detector toolkit such as MediaPipe, the difference is the output. MediaPipe-style pipelines are built around real-time face detection, tracking and mesh topology, and they are optimized for mobile and browser deployment. face-alignment is a Python library whose selling point is the 3D coordinate output and the choice of detector backend, including the folder mode for ground truth boxes. If you need landmarks in a browser or on a phone, this package is not the path. If you need 3D points in a PyTorch training or inference graph, it is.

Maintenance, licensing and upgrade cost

The repository is not archived and the last push was on 2026-04-06, which is the same day v1.5.0 was released. The previous two releases, v1.4.1 and v1.4.0, landed in August and June 2023, so the gap between v1.4.1 and v1.5.0 is roughly two and a half years. Treat releases as occasional rather than continuous.

The licence is BSD-3-Clause, and setup.py declares license='BSD'. That is a permissive licence, but it is worth noting that the package bundles or downloads model weights, and the README does not state a separate licence for those weights. If you are redistributing a product that includes them, check the weight provenance yourself; this is a question for your legal team, not something the README answers.

Upgrade cost is dominated by the PyTorch pin. requirements.txt asks for torch>=2.0.0, and the Dockerfile installs torch==2.11.0 from the cu128 index on top of nvidia/cuda:12.8.0-cudnn-devel-ubuntu22.04. Because torch.compile is enabled by default, a PyTorch major upgrade can change compilation behaviour and first-run latency even when the face-alignment version does not move. Pin both.

Editorial conclusion

Adopt face-alignment when you need 68-point 2D or 3D landmarks inside a Python or PyTorch pipeline and you are willing to pin a PyTorch version and accept a first-run torch.compile cost of roughly 25 seconds. Do not adopt it if you need a documented numerical evaluation harness: the README points to the separate Lua implementation for that, because the Python models are not the ones evaluated in the paper. Before committing, verify the detector you intend to ship against your own images, since YuNet and SCRFD are CPU-only and the README gives no accuracy figures for any backend.

Frequently asked questions

What is face-alignment?

It is a Python library that detects facial landmarks in 2D or 3D coordinates, built on the FAN face alignment network and distributed on PyPI as face-alignment. The README describes it as capable of detecting points in both 2D and 3D coordinates.

How do I install face-alignment?

Run pip install face-alignment. The README lists Python 3.9+ and PyTorch 2.0+ as requirements, and a CUDA GPU as highly recommended for detector performance but not required.

Can face-alignment give an example of face detection?

The README's minimal example constructs FaceAlignment with LandmarksType.TWO_D and flip_input=False, reads an image with skimage.io, then calls fa.get_landmarks(input) to get predictions.

Which face detectors does face-alignment support?

SFD is the default and most accurate but slowest, with BlazeFace, YuNet, RetinaFace, SCRFD and a deprecated dlib backend also available via the face_detector argument. YuNet and SCRFD are CPU only, and SCRFD requires the optional onnxruntime package.

Why is the first face-alignment run slow?

The README states the landmark network is compiled with torch.compile by default, and that only the first run is slow at roughly 25 seconds because compilation artifacts are cached to disk. Pass compile=False to skip it.

Official sources

  1. 1adrianb/face-alignment on GitHub
  2. License: BSD-3-Clause
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/1adrianb-face-alignment.svg)](https://hysenlabs.com/projects/1adrianb-face-alignment)