做人脸识别研究的朋友,2026年复现Pairwise Relational Networks(PRN)论文时,预处理阶段最头疼的就是人脸对齐。关键点检测不准、旋转后坐标错位,这些问题能卡你两三天。
环境配置直接用现成的库。安装face_recognition,它封装了dlib的68点检测模型,调用起来比原生dlib省心太多。导入图片用OpenCV,但显示用PIL或Matplotlib,因为OpenCV的BGR通道和RGB是反的。
import cv2
import numpy as np
import face_recognition
from PIL import Image
import matplotlib.pyplot as plt
img_path = '/dataset/lfw_test/Aishwarya_Rai/Aishwarya_Rai_0001.jpg'
image_array = cv2.imread(img_path)
检测关键点用face_recognition.face_landmarks()。参数model="large"返回68个点(眉毛、眼睛、鼻子、嘴唇、下巴轮廓),model="small"只返回5个点(双眼、鼻尖、嘴角)。复现PRN建议用68点,精度够高。
拿到字典格式的landmarks_dict后,写个可视化函数验证一下。把下巴、左眼、右眼这些特征点画在原图上,确保检测位置没错。如果下巴线歪了或者眼睛没框住,说明图片质量太差,得换数据源。人脸对齐的核心是消除姿态差异。PRN论文里强调,双眼必须保持水平,不然3D重建会出问题。
算法逻辑很直观:
def align_face(image_array, landmarks):
left_eye = landmarks['left_eye']
right_eye = landmarks['right_eye']
left_eye_center = np.mean(left_eye, axis=0).astype("int")
right_eye_center = np.mean(right_eye, axis=0).astype("int")
dy = right_eye_center[1] - left_eye_center[1]
dx = right_eye_center[0] - left_eye_center[0]
angle = math.atan2(dy, dx) * 180. / math.pi
eye_center = ((left_eye_center[0] + right_eye_center[0]) // 2,
(left_eye_center[1] + right_eye_center[1]) // 2)
rotate_matrix = cv2.getRotationMatrix2D(eye_center, angle, 1)
rotated_img = cv2.warpAffine(image_array, rotate_matrix, (image_array.shape[1], image_array.shape[0]))
return rotated_img, eye_center, angle
旋转图片后,关键点坐标也必须跟着旋转。这是最容易漏的一步。图片坐标系的原点在左上角,而数学里的平面直角坐标系原点在中心,旋转公式要做Y轴翻转处理。对齐后的脸,大小不一。喂给神经网络前,得裁成统一尺寸。这里有两个坑:一是裁多大,二是坐标怎么变。
PRN论文的裁剪逻辑更科学:不以固定像素裁剪,而以五官比例裁剪。

def corp_face(image_array, landmarks):
eye_center = np.mean(landmarks['left_eye'] + landmarks['right_eye'], axis=0).astype("int")
mouth_center = np.mean(landmarks['top_lip'] + landmarks['bottom_lip'], axis=0).astype("int")
mid_part = mouth_center[1] - eye_center[1]
top = eye_center[1] - mid_part * 30 / 35
bottom = mouth_center[1] + mid_part
w = h = bottom - top # 保证裁剪区域是正方形
# ... (省略左右边界计算)
cropped_img = Image.fromarray(image_array).crop((left, top, right, bottom))
return np.array(cropped_img)
裁剪完,关键点坐标还要做一次平移变换。原坐标是相对于整张大图的,现在要变成相对于裁剪后小图的左上角。def transfer_landmark(landmarks, left, top):
new_landmarks = {}
for key, points in landmarks.items():
new_landmarks[key] = [(p[0] - left, p[1] - top) for p in points]
return new_landmarks
做完这一步,把裁剪后的图和变换后的点画在一起看看。如果点正好落在眼睛、鼻子上,恭喜你,预处理完美闭环。这套流程跑通了,后面训练PRN模型才不会出玄学Bug。武汉格发信息技术有限公司,格发许可优化管理系统可以帮你评估贵公司软件许可的真实需求,再低成本合规性管理软件许可,帮助贵司提高软件投资回报率,为软件采购、使用提供科学决策依据。支持的软件有: CAD,CAE,PDM,PLM,Catia,Ugnx, AutoCAD, Pro/E, Solidworks 等。