aidcard / src /EulerZ.py
gordonchan's picture
Upload 51 files
cc30486 verified
"""
@author: cuny
@file: EulerX.py
@time: 2022/4/1 13:54
@description:
寻找三维z轴旋转角roll,实现:
1. 输入一张三通道图片(四通道、单通道将默认转为三通道)
2. 输出人脸在x轴的转角roll,顺时针为正方向,角度制
"""
import cv2
import numpy as np
from math import asin, pi # -pi/2 ~ pi/2
# 获得人脸的关键点信息
def get_facePoints(src: np.ndarray, fd68):
if len(src.shape) == 2:
src = cv2.cvtColor(src, cv2.COLOR_GRAY2BGR)
elif src.shape[2] == 4:
src = cv2.cvtColor(src, cv2.COLOR_BGRA2BGR)
status, dets, landmarks, _ = fd68.facePointsEuler(src)
if status == 0:
return 0, None, None
elif status == 2:
return 2, None, None
else:
return 1, dets, np.fliplr(landmarks)
def eulerZ(landmark: np.matrix):
# 我们规定顺时针为正方向
def get_pi_2(r):
pi_2 = pi / 2.
if r >= 0.0:
return pi_2
else:
return -pi_2
orbit_points = np.array([[landmark[21, 0], landmark[21, 1]], [landmark[71, 0], landmark[71, 1]],
[landmark[25, 0], landmark[25, 1]], [landmark[67, 0], landmark[67, 1]]])
# [[cos a],[sin a],[point_x],[point_y]]
# 前面两项是有关直线与Y正半轴夹角a的三角函数,所以对于眼睛部分来讲sin a应该接近1
# "我可以认为"cv2.fitLine的y轴正方向为竖直向下,且生成的拟合直线的方向为从起点指向终点
# 与y轴的夹角为y轴夹角与直线方向的夹角,方向从y指向直线,逆时针为正方向
# 所以最后对于鼻梁的计算结果需要取个负号
orbit_line = cv2.fitLine(orbit_points, cv2.DIST_L2, 0, 0.01, 0.01)
orbit_a = asin(orbit_line[1][0])
nose_points = np.array([[landmark[55, 0], landmark[55, 1]], [landmark[69, 0], landmark[69, 1]]])
nose_line = cv2.fitLine(nose_points, cv2.DIST_L2, 0, 0.01, 0.01)
nose_a = asin(nose_line[1][0])
return (orbit_a + nose_a) * (180.0 / (2 * pi))