lllyasviel/Fooocus · error · FaceWarpException

facial_pts.shape must be (K,2) or (2,K) and K>2

Error message

facial_pts.shape must be (K,2) or (2,K) and K>2

What it means

The mirror of the reference-points check: the detected facial_pts (source landmarks) must be shape (K,2) or (2,K) with K>2 so at least three 2-D correspondences exist for transform estimation. Malformed landmark arrays raise FaceWarpException before cv2/warpAffine run.

Source

Thrown at extras/facexlib/detection/align_trans.py:202

            inner_padding_factor = 0
            outer_padding = (0, 0)
            output_size = crop_size

            reference_pts = get_reference_facial_points(output_size, inner_padding_factor, outer_padding,
                                                        default_square)

    ref_pts = np.float32(reference_pts)
    ref_pts_shp = ref_pts.shape
    if max(ref_pts_shp) < 3 or min(ref_pts_shp) != 2:
        raise FaceWarpException('reference_pts.shape must be (K,2) or (2,K) and K>2')

    if ref_pts_shp[0] == 2:
        ref_pts = ref_pts.T

    src_pts = np.float32(facial_pts)
    src_pts_shp = src_pts.shape
    if max(src_pts_shp) < 3 or min(src_pts_shp) != 2:
        raise FaceWarpException('facial_pts.shape must be (K,2) or (2,K) and K>2')

    if src_pts_shp[0] == 2:
        src_pts = src_pts.T

    if src_pts.shape != ref_pts.shape:
        raise FaceWarpException('facial_pts and reference_pts must have the same shape')

    if align_type == 'cv2_affine':
        tfm = cv2.getAffineTransform(src_pts[0:3], ref_pts[0:3])
    elif align_type == 'affine':
        tfm = get_affine_transform_matrix(src_pts, ref_pts)
    else:
        tfm = get_similarity_transform_for_cv2(src_pts, ref_pts)

    face_img = cv2.warpAffine(src_img, tfm, (crop_size[0], crop_size[1]))

    return face_img

View on GitHub (pinned to ae05379cc9)

Solutions

  1. Reshape the landmarks to (5,2): np.asarray(pts, dtype=np.float32).reshape(-1,2)
  2. Drop any third column: pts = pts[:, :2]
  3. Check the detector returns 5 facial landmarks (eyes, nose, mouth corners) as expected by this alignment API

Example fix

// before
face_img = warp_and_crop_face(img, landmarks.ravel())

// after
face_img = warp_and_crop_face(img, np.asarray(landmarks, dtype=np.float32).reshape(5,2))
Defensive patterns

Strategy: type-guard

Validate before calling

import numpy as np
src = np.asarray(facial_pts, dtype=np.float32)
assert src.ndim == 2 and min(src.shape) == 2 and max(src.shape) >= 3, \
    'facial_pts must be (K,2)/(2,K) with K>2'
if src.shape[0] == 2:
    src = src.T

Type guard

def is_valid_landmarks(pts) -> bool:
    import numpy as np
    a = np.asarray(pts)
    return a.ndim == 2 and min(a.shape) == 2 and max(a.shape) >= 3

Prevention

When it happens

Trigger: Passing the detector's raw output without reshaping (flat 10-vector for 5 landmarks), a single point, an empty array, or landmarks with a third coordinate column (K,3).

Common situations: Detector API changes (different landmark layout); passing bounding-box corners instead of landmarks; landmarks stored as dict values iterated incorrectly.

Related errors


AI-assisted analysis of lllyasviel/Fooocus@ae05379cc9 (2026-08-15). Data as JSON: /api/errors/9f55719c83fc95b1. Report an issue: GitHub.