Skip to content

Face analysis

dynaface.facial

Face analysis: find a face, place its landmarks, crop it and run the measures.

load_face_image() loads a photo from a file or URL. For images you already hold as RGB NumPy arrays, such as video frames, create an AnalyzeFace and call its load_image().

AnalyzeFace

AnalyzeFace(
    measures: Optional[List[MeasureBase]] = None,
    tilt_threshold: float = DEFAULT_TILT_THRESHOLD,
)

Bases: ImageAnalysis

Analyzes a face: finds it in an image, places its 98 landmarks, crops it to a standard size and runs the measures on it.

Load the models with dynaface.models.init_models() first. Then call load_image() with an RGB image and analyze() for the measurements. The image with the measures drawn on it is in render_img, and save() writes it to a file.

Attributes:

Name Type Description
pd float

The assumed distance between the pupils, in millimeters (63 by default), used to convert pixels to millimeters. Set it on the class, as AnalyzeFace.pd, to calibrate.

measures List[MeasureBase]

The measures that analyze() runs.

landmarks List[Tuple[int, int]]

The 98 WFLW landmark positions, in pixels of the current image.

pose Pose

The pose that load_image() detected or was told to use.

render_img NDArray[uint8]

The image the measures draw on.

Initialize the AnalyzeFace object.

Parameters:

Name Type Description Default
measures Optional[List[MeasureBase]]

Facial measures to be used. Defaults to None.

None
tilt_threshold float

Maximum allowable tilt threshold. Defaults to DEFAULT_TILT_THRESHOLD.

DEFAULT_TILT_THRESHOLD

get_all_items

get_all_items() -> List[str]

List the outputs to show or export: the enabled items of the enabled measures, without display-only items.

analyze() returns every output whether or not its item is enabled, so use this list to choose which ones to show.

Returns:

Type Description
List[str]

List[str]: Output names, such as "fai" and "oce.l".

is_no_face

is_no_face() -> bool

Check if no face is detected.

Returns:

Name Type Description
bool bool

True if no face is detected, False otherwise.

load_image

load_image(
    img: NDArray[Any],
    crop: Optional[bool] = True,
    pupils: Optional[
        Tuple[Tuple[int, int], Tuple[int, int]]
    ] = None,
    force_pose: Optional[Pose] = Pose.DETECT,
) -> bool

Load an RGB image, find the face, place its landmarks and crop it.

Parameters:

Name Type Description Default
img NDArray[Any]

The image, as an RGB array.

required
crop bool

Whether to crop the face to the standard 1024 by 1024 size. Lateral faces are always cropped.

True
pupils Optional[Tuple[Tuple[int, int], Tuple[int, int]]]

Currently unused; the crop is always placed using the pupils found in this image.

None
force_pose Optional[Pose]

Pose.DETECT to classify the pose as frontal or lateral, or a Pose to use instead.

DETECT

Returns:

Name Type Description
bool bool

True once the image is loaded.

draw_landmarks

draw_landmarks(
    size: float = 0.25,
    color: Tuple[int, int, int] = (0, 255, 255),
    numbers: bool = False,
    only: Optional[Iterable[int]] = None,
) -> None

Draw landmarks (and optionally their indices) on the image.

Parameters:

Name Type Description Default
size float

Visual scale factor for landmark dots and number labels.

0.25
color Tuple[int, int, int]

BGR color for drawing.

(0, 255, 255)
numbers bool

If True, draw the landmark index next to each point.

False
only Iterable[int] | None

If provided, draw ONLY these landmark indices. If None, draw all landmarks.

None

measure

measure(
    pt1: Tuple[int, int],
    pt2: Tuple[int, int],
    color: Tuple[int, int, int] = (255, 0, 0),
    thickness: int = 3,
    render: bool = True,
    dir: str = "r",
) -> float

Measures the Euclidean distance between two points (pt1 and pt2) and optionally renders an arrow and text.

measure_curve

measure_curve(
    pt1: Tuple[int, int],
    pt2: Tuple[int, int],
    sagittal_x: NDArray[Any],
    sagittal_y: NDArray[Any],
    color: Tuple[int, int, int] = (255, 0, 0),
    thickness: int = 3,
    render: bool = True,
    dir: str = "r",
) -> float

Measures the curved distance along a sagittal line between two points (pt1 and pt2) and optionally renders the curve and text.

draw_curve

draw_curve(
    segment: NDArray[Any],
    color: Tuple[int, int, int],
    thickness: int,
) -> None

Draws a curve connecting a segment of points.

analyze_next_pt

analyze_next_pt(txt: str) -> Tuple[int, int]

Determines the next position for analysis text based on current position.

analyze

analyze() -> Optional[Dict[str, Any]]

Run the enabled measures on the face, drawing them on render_img.

Returns:

Type Description
Optional[Dict[str, Any]]

Optional[Dict[str, Any]]: Each output's name mapped to its value, such as {"fai": 0.70, "oce.l": 30.12, ...}, or None if the image has no landmarks. A value that couldn't be determined is NaN.

calculate_face_rotation

calculate_face_rotation() -> float

Calculates the face rotation in degrees.

crop_lateral

crop_lateral() -> None

Crop to 1024×1024 for lateral analysis, guaranteeing that ALL landmarks are visible vertically, plus configurable top/bottom padding.

  • Scale is chosen so (landmark_band + pads) fits within 1024 px height.
  • Horizontally, the profile's leading edge (leftmost landmark; the face always faces left here) is placed LATERAL_LEFT_MARGIN_RATIO from the left, so the face uses the space at the left and the sagittal chart overlaid at the right cuts off near the front of the ear.
  • If the source is narrow, side padding is allowed (pillarbox) so that vertical padding is never silently squeezed away.

crop_stylegan

crop_stylegan(
    pupils: Optional[
        Tuple[Tuple[int, int], Tuple[int, int]]
    ] = None,
) -> None

Processes and crops the image for StyleGAN.

calc_pd

calc_pd() -> None

Measure the pupils on the current landmarks; update pupillary_distance and pix2mm (millimeters per pixel).

get_pupils

get_pupils() -> (
    Tuple[Tuple[float, float], Tuple[float, float]]
)

Return the two pupil positions, left first.

Returns:

Type Description
Tuple[Tuple[float, float], Tuple[float, float]]

Tuple[Tuple[float, float], Tuple[float, float]]: The left and right pupil landmarks, in pixels.

dump_state

dump_state() -> List[Any]

Capture this frame's analysis, so a video's frames can be kept and restored with load_state() without detecting the face again.

Returns:

Type Description
List[Any]

List[Any]: The original image, head pose, landmarks, pupillary distance, millimeters per pixel and face rotation.

load_state

load_state(obj: List[Any]) -> None

Restore a frame's analysis captured by dump_state().

Parameters:

Name Type Description Default
obj List[Any]

The list dump_state() returned. A state saved without a face rotation restores with a rotation of 0.

required

find_pupils

find_pupils() -> (
    Tuple[Tuple[float, float], Tuple[float, float]]
)

Return the two pupil positions, left first. The same as get_pupils().

Returns:

Type Description
Tuple[Tuple[float, float], Tuple[float, float]]

Tuple[Tuple[float, float], Tuple[float, float]]: The left and right pupil landmarks, in pixels.

calc_bisect

calc_bisect() -> Any

Return the line that bisects the face: perpendicular to the line between the pupils, through its midpoint.

Returns:

Name Type Description
Any Any

The line's two end points on a 1024 by 1024 image.

draw_static

draw_static() -> None

Write the pose, such as "Frontal" or "Lateral (left)", at the bottom left of render_img.

util_calc_pd

util_calc_pd(
    pupils: Tuple[Tuple[float, float], Tuple[float, float]],
) -> Tuple[float, float]

Measure the distance between the pupils and the millimeters per pixel.

The scale assumes the pupils are AnalyzeFace.pd millimeters apart.

Parameters:

Name Type Description Default
pupils Tuple[Tuple[float, float], Tuple[float, float]]

The two pupil positions, in pixels.

required

Returns:

Type Description
Tuple[float, float]

Tuple[float, float]: The pupillary distance in pixels, and the millimeters per pixel, which is NaN when the pupils coincide.

util_get_pupils

util_get_pupils(
    landmarks: List[Tuple[int, int]],
) -> Tuple[Tuple[int, int], Tuple[int, int]]

Return the two pupil landmarks, left first.

Parameters:

Name Type Description Default
landmarks List[Tuple[int, int]]

The 98 WFLW landmarks.

required

Returns:

Type Description
Tuple[Tuple[int, int], Tuple[int, int]]

Tuple[Tuple[int, int], Tuple[int, int]]: The left pupil (landmark 97) and the right pupil (landmark 96).

load_face_image

load_face_image(
    filename: str,
    crop: bool = True,
    measures: Optional[List[MeasureBase]] = None,
    tilt_threshold: float = DEFAULT_TILT_THRESHOLD,
) -> AnalyzeFace

Load a face image from a file or URL and get it ready to analyze.

Load the models with dynaface.models.init_models() first.

Parameters:

Name Type Description Default
filename str

A path to an image file, or an http or https URL.

required
crop bool

Whether to crop the face to the standard 1024 by 1024 size.

True
measures Optional[List[MeasureBase]]

The measures to run. Defaults to all_measures().

None
tilt_threshold float

Straighten faces tilted more than this many degrees. A negative value, the default, never straightens.

DEFAULT_TILT_THRESHOLD

Returns:

Name Type Description
AnalyzeFace AnalyzeFace

The face, ready for analyze().