{"record":{"id":"9f55719c83fc95b1","repo":"lllyasviel/Fooocus","slug":"facial-pts-shape-must-be-k-2-or-2-k-and-k-2","errorCode":null,"errorMessage":"facial_pts.shape must be (K,2) or (2,K) and K>2","messagePattern":"facial_pts\\.shape must be \\(K,2\\) or \\(2,K\\) and K>2","errorType":"validation","errorClass":"FaceWarpException","httpStatus":null,"severity":"error","filePath":"extras/facexlib/detection/align_trans.py","lineNumber":202,"sourceCode":"            inner_padding_factor = 0\n            outer_padding = (0, 0)\n            output_size = crop_size\n\n            reference_pts = get_reference_facial_points(output_size, inner_padding_factor, outer_padding,\n                                                        default_square)\n\n    ref_pts = np.float32(reference_pts)\n    ref_pts_shp = ref_pts.shape\n    if max(ref_pts_shp) < 3 or min(ref_pts_shp) != 2:\n        raise FaceWarpException('reference_pts.shape must be (K,2) or (2,K) and K>2')\n\n    if ref_pts_shp[0] == 2:\n        ref_pts = ref_pts.T\n\n    src_pts = np.float32(facial_pts)\n    src_pts_shp = src_pts.shape\n    if max(src_pts_shp) < 3 or min(src_pts_shp) != 2:\n        raise FaceWarpException('facial_pts.shape must be (K,2) or (2,K) and K>2')\n\n    if src_pts_shp[0] == 2:\n        src_pts = src_pts.T\n\n    if src_pts.shape != ref_pts.shape:\n        raise FaceWarpException('facial_pts and reference_pts must have the same shape')\n\n    if align_type == 'cv2_affine':\n        tfm = cv2.getAffineTransform(src_pts[0:3], ref_pts[0:3])\n    elif align_type == 'affine':\n        tfm = get_affine_transform_matrix(src_pts, ref_pts)\n    else:\n        tfm = get_similarity_transform_for_cv2(src_pts, ref_pts)\n\n    face_img = cv2.warpAffine(src_img, tfm, (crop_size[0], crop_size[1]))\n\n    return face_img\n","sourceCodeStart":184,"sourceCodeEnd":220,"githubUrl":"https://github.com/lllyasviel/Fooocus/blob/ae05379cc97bc4361ec8b4ec90193dab21be763f/extras/facexlib/detection/align_trans.py#L184-L220","documentation":"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.","triggerScenarios":"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).","commonSituations":"Detector API changes (different landmark layout); passing bounding-box corners instead of landmarks; landmarks stored as dict values iterated incorrectly.","solutions":["Reshape the landmarks to (5,2): np.asarray(pts, dtype=np.float32).reshape(-1,2)","Drop any third column: pts = pts[:, :2]","Check the detector returns 5 facial landmarks (eyes, nose, mouth corners) as expected by this alignment API"],"exampleFix":"// before\nface_img = warp_and_crop_face(img, landmarks.ravel())\n\n// after\nface_img = warp_and_crop_face(img, np.asarray(landmarks, dtype=np.float32).reshape(5,2))","handlingStrategy":"type-guard","validationCode":"import numpy as np\nsrc = np.asarray(facial_pts, dtype=np.float32)\nassert src.ndim == 2 and min(src.shape) == 2 and max(src.shape) >= 3, \\\n    'facial_pts must be (K,2)/(2,K) with K>2'\nif src.shape[0] == 2:\n    src = src.T","typeGuard":"def is_valid_landmarks(pts) -> bool:\n    import numpy as np\n    a = np.asarray(pts)\n    return a.ndim == 2 and min(a.shape) == 2 and max(a.shape) >= 3","tryCatchPattern":null,"preventionTips":["Reshape detector output to (5,2) immediately after detection","Pin the detector's landmark format in a wrapper function","Drop extra columns (K,3 -> K,2) before alignment"],"tags":["facexlib","face-alignment","landmarks","shape-validation"],"backgroundTag":null,"analyzedSha":"ae05379cc97bc4361ec8b4ec90193dab21be763f","analyzedAt":"2026-08-15T04:23:59.533Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}