4. 人脸对齐

任务说明

本案例实现人脸对齐的核心流程:给定一张人脸图像及检测到的两只眼睛关键点坐标,通过仿射变换将人脸旋转至眼睛水平,并裁剪出标准化尺寸的人脸区域。输入为图像文件路径与两眼坐标,输出为对齐并裁剪后的标准人脸图像。

实现方案

采用OpenCV完成全部计算。核心步骤为:根据两眼坐标计算旋转角度,构造旋转矩阵(以两眼中心为旋转中心),执行仿射变换,最后按标准人脸几何比例裁剪出固定尺寸区域。裁剪区域依据两眼距离确定宽度,再按比例推算高度,保证不同人脸图像输出尺寸一致。

人脸对齐仿射变换流程 原始人脸图像 左眼 (x₁,y₁) 右眼 (x₂,y₂) 角度计算 θ = atan2(y₂-y₁, x₂-x₁) 旋转角 = -θ × 180/π 构造旋转矩阵 中心 = 两眼中心 M = getRotationMatrix2D 仿射变换 warpAffine 旋转+缩放 标准化裁剪 宽 = 2.2 × 眼距 高 = 宽 × 0.75 输出对齐人脸 固定尺寸 220×165 眼睛保持水平

代码实现


import cv2
import numpy as np

def align_face(image_path, left_eye, right_eye, output_size=(220, 165)):
    """
    人脸对齐:旋转使眼睛水平,并裁剪标准化区域
    
    参数:
        image_path: 输入图像路径
        left_eye:  左眼坐标 (x, y)
        right_eye: 右眼坐标 (x, y)
        output_size: 输出尺寸 (宽, 高)
    
    返回:
        对齐并裁剪后的人脸图像 (numpy数组)
    """
    # 读取图像
    img = cv2.imread(image_path)
    if img is None:
        raise ValueError(f"无法读取图像: {image_path}")
    
    # 计算旋转角度(弧度)
    dx = right_eye[0] - left_eye[0]
    dy = right_eye[1] - left_eye[1]
    angle_rad = np.arctan2(dy, dx)
    angle_deg = -np.degrees(angle_rad)  # 负号:顺时针旋转使眼睛水平
    
    # 两眼中心作为旋转中心
    eye_center = ((left_eye[0] + right_eye[0]) / 2.0,
                  (left_eye[1] + right_eye[1]) / 2.0)
    
    # 构造旋转矩阵(含缩放)
    rot_matrix = cv2.getRotationMatrix2D(eye_center, angle_deg, scale=1.0)
    
    # 执行仿射变换
    h, w = img.shape[:2]
    rotated = cv2.warpAffine(img, rot_matrix, (w, h),
                             flags=cv2.INTER_CUBIC,
                             borderMode=cv2.BORDER_REPLICATE)
    
    # 计算标准化裁剪区域
    eye_dist = np.sqrt(dx**2 + dy**2)
    crop_w = int(2.2 * eye_dist)      # 宽度 = 2.2倍眼距
    crop_h = int(crop_w * 0.75)       # 高度 = 宽度的0.75
    
    # 裁剪中心 = 旋转后的两眼中心
    # 旋转后两眼中心位置不变(旋转中心即两眼中心)
    cx, cy = int(eye_center[0]), int(eye_center[1])
    
    # 计算裁剪矩形(越界处理)
    x1 = max(0, cx - crop_w // 2)
    y1 = max(0, cy - crop_h // 2)
    x2 = min(w, x1 + crop_w)
    y2 = min(h, y1 + crop_h)
    
    cropped = rotated[y1:y2, x1:x2]
    
    # 缩放到标准输出尺寸
    aligned = cv2.resize(cropped, output_size, interpolation=cv2.INTER_CUBIC)
    
    return aligned

# 示例:使用给定关键点执行对齐
if __name__ == "__main__":
    # 输入图像(请替换为实际路径)
    img_path = "face.jpg"
    
    # 示例关键点(左眼、右眼坐标)
    left_eye_pt = (112, 98)
    right_eye_pt = (168, 102)
    
    # 执行对齐
    result = align_face(img_path, left_eye_pt, right_eye_pt)
    
    # 保存结果
    cv2.imwrite("aligned_face.jpg", result)
    print("对齐完成,输出尺寸:", result.shape[1], "x", result.shape[0])

落地与验证

依赖安装:需要OpenCV与NumPy,执行 pip install opencv-python numpy。

运行方式:将代码保存为 face_align.py,准备一张含正脸人脸的图像 face.jpg,修改代码中两眼坐标为你图像中的实际关键点位置,然后执行 python face_align.py。

验证方法:程序运行后生成 aligned_face.jpg。打开该图像,观察以下判定标准:

  • 两只眼睛中心处于同一水平线(y坐标差不超过2像素);
  • 输出图像尺寸为220×165像素;
  • 人脸位于图像中央,双眼完整可见。

若眼睛仍倾斜,说明输入关键点坐标不准确,请重新标注后再次运行。