Aidlux人脸识别全流程二:人头姿态估计

一、人头姿态估计

在动态人脸识别(无感知人脸识别)中,使用较高精度的人脸检测器时,由于各个摄像头角度的差异,或者因为光线原因,会出现许多无效的人脸,例如低头、侧脸、黑脸(光线原因),等,这其中低头和侧脸尤为严重(在知道这里有一个摄像头的情况下没人能拒绝看一眼),这个时候我们需要用到人脸姿态估计,为人脸特征提取器提前过滤掉这些无效人脸,加快人脸识别全流程的速度。

什么是位姿估计?

在计算机视觉中,物体的姿态是指物体相对于相机的相对方向和位置。你可以通过物体相对于相机移动,或者相机相对于物体移动来改变位姿。—— 这二者对于改变位姿是等价的,因为它们之间的关系是相对的。

位姿估计问题通常被称为“Perspective-n-Point” 问题,或计算机视觉中的PnP 问题。PnP 问题的目标是找到一个物体的位姿,我们需要具备两个条件:

条件1: 有一个已经校准了的相机;

条件2: 我们知道物体上的n 个3D 点的位置locations 和这些3D点在图像中相应的2D投影。

什么是欧拉角?

欧拉角分为3个角,分别叫做俯仰角pitch(绕x轴旋转)、偏航角yaw(绕y轴旋转)和翻滚角roll(绕z轴旋转),我们所说的头部姿态估计主要就是通过算法求出这几个角。

二、实现步骤

进行人头姿态估计所需要的信息

1.使用retinaface预测的五个关键点坐标

2.一个标准的头部3D模型中的与retinaface预测的五个关键点对应的3D坐标

(0.0, 0.0, 0.0),  # Nose tip
(-125.0, 170.0, -135.0),  # Left eye left corner
(125.0, 170.0, -135.0),  # Right eye right corne
(-150.0, -150.0, -125.0),  # Left Mouth corner
(150.0, -150.0, -125.0)  # Right mouth corner

3.相机的内参 (需要标定),可以做近似的处理:

(1)用图像中心近似 光学中心 ;(2)用图像的像素宽度近似 相机的焦距 ;(3)假定不存在径向畸变。

def camera_internals(self, img_size):
    # Camera internals 相机标定
    center = (img_size[1] / 2, img_size[0] / 2)
    focal_length = center[0] / np.tan(60 / 2 * np.pi / 180)
    self.camera_matrix = np.array(
        [[focal_length, 0, center[0]],
         [0, focal_length, center[1]],
         [0, 0, 1]], dtype="double")

得到我们所需要的信息后,使用OpenCV提供的位姿估计的算法,进行求解,得到旋转向量(平移向量不需要):

# model_points 标准的人头3D模型坐标点
# image_points 与之对应的预测出来的2D人脸坐标点
# camera_matrix 相机内参
# dist_coeffs = dist_coeffs = np.zeros((4, 1)) 假定没有镜头畸变
(success, rotation_vector, translation_vector) = 
cv2.solvePnP(self.model_points, image_points, self.camera_matrix, dist_coeffs, flags=cv2.SOLVEPNP_EPNP)

通过罗德里格斯公式将旋转向量和旋转矩阵之间进行转换

rvec_matrix = cv2.Rodrigues(rotation_vector)[0]

分解投影矩阵获得欧拉角

proj_matrix = np.hstack((rvec_matrix, translation_vector))
eulerAngles = cv2.decomposeProjectionMatrix(proj_matrix)[6]

将欧拉角转化为具体的角度:

pitch, yaw, roll = [math.radians(_) for _ in eulerAngles]
pitch = math.degrees(math.asin(math.sin(pitch)))
roll = -math.degrees(math.asin(math.sin(roll)))
yaw = math.degrees(math.asin(math.sin(yaw)))

得到这几个欧拉角后,我们可以将俯仰角和偏航角过大的人脸过滤掉,提升程序性能的同时也可以防止一些误识别的出现。

为什么不过滤翻滚角呢?这是因为在后面的人脸矫正中,我们可以将翻滚角比较大的人脸矫正成正对的人脸,对后续的特征提取造成的影响不是很大。

三、实现效果

四、预告

人脸特征提取预处理2之人脸矫正。

?