A comprehensive 2D and 3D face analysis toolkit with state-of-the-art algorithms for face recognition, detection, and alignment.
—
Comprehensive utilities for face alignment, transformation, and preprocessing including normalization, cropping, coordinate transformations, and geometric operations on facial landmarks and images.
Functions for normalizing face regions based on facial landmarks for consistent processing.
def norm_crop(img, landmark, image_size=112, mode='arcface') -> np.ndarray:
"""
Normalize and crop face region based on landmarks.
Parameters:
- img: np.ndarray, input image
- landmark: np.ndarray, facial landmarks, shape (5, 2) or (68, 2)
- image_size: int, output image size (square)
- mode: str, alignment mode ('arcface', 'ffhq')
Returns:
np.ndarray: normalized and cropped face image
"""
def norm_crop2(img, landmark, image_size=112, mode='arcface') -> Tuple[np.ndarray, np.ndarray]:
"""
Normalize and crop face with transformation matrix.
Parameters: same as norm_crop
Returns:
tuple: (cropped_face, transformation_matrix)
- cropped_face: np.ndarray, normalized face image
- transformation_matrix: np.ndarray, 2x3 affine transformation matrix
"""
def estimate_norm(lmk, image_size=112, mode='arcface') -> np.ndarray:
"""
Estimate normalization transformation matrix from landmarks.
Parameters:
- lmk: np.ndarray, facial landmarks
- image_size: int, target image size
- mode: str, alignment mode
Returns:
np.ndarray: 2x3 affine transformation matrix
"""
def square_crop(im, S) -> Tuple[np.ndarray, float]:
"""
Crop image to square with scaling.
Parameters:
- im: np.ndarray, input image
- S: int, target square size
Returns:
tuple: (cropped_image, scale_factor)
"""Functions for applying geometric transformations to images and point coordinates.
def transform(data, center, output_size, scale, rotation) -> Tuple[np.ndarray, np.ndarray]:
"""
Apply geometric transformation to image data.
Parameters:
- data: np.ndarray, input image
- center: tuple, center point (x, y)
- output_size: tuple, output size (width, height)
- scale: float, scaling factor
- rotation: float, rotation angle in degrees
Returns:
tuple: (transformed_image, transformation_matrix)
"""
def trans_points2d(pts, M) -> np.ndarray:
"""
Transform 2D points using affine transformation matrix.
Parameters:
- pts: np.ndarray, 2D points, shape (N, 2)
- M: np.ndarray, 2x3 or 3x3 transformation matrix
Returns:
np.ndarray: transformed points, shape (N, 2)
"""
def trans_points3d(pts, M) -> np.ndarray:
"""
Transform 3D points using transformation matrix.
Parameters:
- pts: np.ndarray, 3D points, shape (N, 3)
- M: np.ndarray, 3x3 or 4x4 transformation matrix
Returns:
np.ndarray: transformed points, shape (N, 3)
"""
def trans_points(pts, M) -> np.ndarray:
"""
Transform points (auto-detects 2D or 3D).
Parameters:
- pts: np.ndarray, points to transform
- M: np.ndarray, transformation matrix
Returns:
np.ndarray: transformed points
"""Advanced functions for 3D facial geometry processing and pose estimation.
def estimate_affine_matrix_3d23d(X, Y) -> np.ndarray:
"""
Estimate 3D-to-3D affine transformation matrix.
Parameters:
- X: np.ndarray, source 3D points, shape (N, 3)
- Y: np.ndarray, target 3D points, shape (N, 3)
Returns:
np.ndarray: 4x4 affine transformation matrix
"""
def P2sRt(P) -> Tuple[float, np.ndarray, np.ndarray]:
"""
Decompose projection matrix into scale, rotation, and translation.
Parameters:
- P: np.ndarray, 3x4 projection matrix
Returns:
tuple: (scale, rotation_matrix, translation_vector)
- scale: float, scaling factor
- rotation_matrix: np.ndarray, 3x3 rotation matrix
- translation_vector: np.ndarray, 3D translation vector
"""
def matrix2angle(R) -> Tuple[float, float, float]:
"""
Convert rotation matrix to Euler angles.
Parameters:
- R: np.ndarray, 3x3 rotation matrix
Returns:
tuple: (pitch, yaw, roll) angles in radians
"""import cv2
import numpy as np
from insightface.utils.face_align import norm_crop, estimate_norm
# Load image and detect landmarks
img = cv2.imread('face.jpg')
# Assume landmarks detected: shape (5, 2) for 5-point landmarks
landmarks = np.array([[38.2946, 51.6963],
[73.5318, 51.5014],
[56.0252, 71.7366],
[41.5493, 92.3655],
[70.7299, 92.2041]])
# Normalize face for recognition model input
aligned_face = norm_crop(img, landmarks, image_size=112, mode='arcface')
# Save aligned face
cv2.imwrite('aligned_face.jpg', aligned_face)
print(f"Aligned face shape: {aligned_face.shape}") # (112, 112, 3)# Get both aligned face and transformation matrix
aligned_face, transform_matrix = norm_crop2(img, landmarks, image_size=112)
print(f"Transform matrix shape: {transform_matrix.shape}") # (2, 3)
print(f"Transform matrix:\n{transform_matrix}")
# Apply same transformation to other points
additional_landmarks = np.array([[45, 85], [65, 85]]) # chin points
transformed_landmarks = trans_points2d(additional_landmarks, transform_matrix)
print(f"Transformed chin points: {transformed_landmarks}")from insightface.app import FaceAnalysis
app = FaceAnalysis()
app.prepare(ctx_id=0)
def align_faces_from_detection(img, faces):
"""Align all detected faces in an image."""
aligned_faces = []
for face in faces:
if face.kps is not None:
# Use 5-point landmarks for alignment
aligned = norm_crop(img, face.kps, image_size=112, mode='arcface')
aligned_faces.append(aligned)
return aligned_faces
# Process image
img = cv2.imread('group_photo.jpg')
faces = app.get(img)
aligned_faces = align_faces_from_detection(img, faces)
print(f"Aligned {len(aligned_faces)} faces")
for i, aligned in enumerate(aligned_faces):
cv2.imwrite(f'aligned_face_{i}.jpg', aligned)import numpy as np
from insightface.utils.transform import matrix2angle, P2sRt
# Example: Process 3D landmarks for pose estimation
def estimate_head_pose(landmarks_3d):
"""Estimate head pose from 3D landmarks."""
# Select key points for pose estimation
nose_tip = landmarks_3d[30] # Nose tip
left_eye = landmarks_3d[36] # Left eye corner
right_eye = landmarks_3d[45] # Right eye corner
left_mouth = landmarks_3d[48] # Left mouth corner
right_mouth = landmarks_3d[54] # Right mouth corner
# Create reference points (canonical face)
ref_points = np.array([
[0, 0, 0], # Nose tip (origin)
[-30, -20, -5], # Left eye
[30, -20, -5], # Right eye
[-20, 20, -5], # Left mouth
[20, 20, -5] # Right mouth
])
face_points = np.array([nose_tip, left_eye, right_eye, left_mouth, right_mouth])
# Estimate transformation
transform_matrix = estimate_affine_matrix_3d23d(ref_points, face_points)
# Extract rotation matrix and convert to angles
rotation_matrix = transform_matrix[:3, :3]
pitch, yaw, roll = matrix2angle(rotation_matrix)
return np.degrees([pitch, yaw, roll])
# Example usage with 3D landmarks
if hasattr(face, 'landmark_3d_68') and face.landmark_3d_68 is not None:
pose_angles = estimate_head_pose(face.landmark_3d_68)
print(f"Head pose - Pitch: {pose_angles[0]:.1f}°, Yaw: {pose_angles[1]:.1f}°, Roll: {pose_angles[2]:.1f}°")def preprocess_face_for_model(img, face, target_size=112, mode='arcface'):
"""
Complete preprocessing pipeline for face recognition.
Parameters:
- img: input image
- face: Face object with landmarks
- target_size: output image size
- mode: alignment mode
Returns:
- preprocessed face ready for model input
"""
if face.kps is None:
# Fallback: use bounding box center
x1, y1, x2, y2 = face.bbox
center_x, center_y = (x1 + x2) / 2, (y1 + y2) / 2
# Create approximate landmarks for alignment
face_width = x2 - x1
eye_y = y1 + face_width * 0.35
landmarks = np.array([
[x1 + face_width * 0.3, eye_y], # Left eye approx
[x1 + face_width * 0.7, eye_y], # Right eye approx
[center_x, y1 + face_width * 0.6], # Nose approx
[x1 + face_width * 0.35, y1 + face_width * 0.8], # Left mouth
[x1 + face_width * 0.65, y1 + face_width * 0.8] # Right mouth
])
else:
landmarks = face.kps
# Align and normalize face
aligned_face = norm_crop(img, landmarks, image_size=target_size, mode=mode)
# Additional preprocessing (normalize pixel values)
aligned_face = aligned_face.astype(np.float32)
aligned_face = (aligned_face - 127.5) / 128.0 # Normalize to [-1, 1]
return aligned_face
# Usage
preprocessed = preprocess_face_for_model(img, face)
print(f"Preprocessed face shape: {preprocessed.shape}")
print(f"Value range: [{preprocessed.min():.3f}, {preprocessed.max():.3f}]")def validate_alignment_quality(original_landmarks, aligned_landmarks, transform_matrix):
"""Validate face alignment quality by checking landmark consistency."""
# Apply transformation to original landmarks
predicted_landmarks = trans_points2d(original_landmarks, transform_matrix)
# Calculate alignment error
error = np.mean(np.linalg.norm(predicted_landmarks - aligned_landmarks, axis=1))
return error
# Example usage
original_kps = face.kps
aligned_face, transform_matrix = norm_crop2(img, original_kps, image_size=112)
# In aligned image, estimate where landmarks should be
expected_kps = np.array([[38, 51], [73, 51], [56, 71], [41, 92], [70, 92]])
error = validate_alignment_quality(original_kps, expected_kps, transform_matrix)
print(f"Alignment error: {error:.2f} pixels")
if error > 5.0:
print("Warning: Poor alignment quality detected")Install with Tessl CLI
npx tessl i tessl/pypi-insightface