出发点:看了很多有关旋转人脸的,多为使用c语言实现的,结合前辈思想使用python实现了一版。
注意:本人使用的是jupyter notebook边写边检查, 所以使用IDE的童鞋记得将我函数定义代码和测试代码分开,测试代码放到
“if __name__=='__main__'”中,可以规范点。
流程为:
1.获得人脸特征点
2.获得左右眼角
3.计算左右眼角坐标差值dx,dy然后求artan值转换为弧度angle
4.选定鼻尖为人脸中心center
5.创建旋转矩阵
6.warpAffine旋转图片
import cv2
import dlib
import numpy as np
import math
shape_path = './shape_predictor_68_face_landmarks.dat' # 特征检测器模型路径
img = cv2.imread('./test/test.jpg') # 测试图片
detector = dlib.get_frontal_face_detector() # 人脸检测器
predictor = dlib.shape_predictor(shape_path) # 人脸特征检测器
# 用来取得特征点集合
def getRes(img):
# 在这里需要将BGR格式颜色通道转为RGB,因为dlib默认使用RGB图片
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
res = detector(img, 1) # 检测结果
for idx,face in enumerate(res): # 遍历检测结果中的人脸
shape = predictor(img, face) # 检测图像中人脸的特征点
return shape
# 用来取得左右眼眼角,鼻尖坐标
def getLocation(shape, img_, debug):
left_eye_x = shape.parts()[36].x # 36对应左眼角
left_eye_y = shape.parts()[36].y
right_eye_x = shape.parts()[45].x # 45对应右眼角
right_eye_y = shape.parts()[45].y
center = shape.parts()[30].x, shape.parts()[30].y
if debug:
cv2.circle(img_, (left_eye_x, left_eye_y), 2, (255,0,0), 2)
cv2.circle(img_, (right_eye_x, right_eye_y), 2, (255,0,0), 2)
cv2.circle(img_, center, 2, (255,0,0), 2)
return left_eye_x, left_eye_y, right_eye_x, right_eye_y, center, img_
# 测试一下
shape = getRes(img)
result = getLocation(shape, img, True)
img_ = result[-1] # 获取标点后图片
# 显示测试图片
cv2.imshow('img_', img_)
cv2.waitKey()
cv2.destroyAllWindows()
# 测试无误,继续
#计算两眼的角度
#原理:
#y/x = tan(角度)
#arctan(y/x) = 弧度
#度化弧度: 180° = π弧度 则:1° = π弧度/180
#弧度化度: π弧度 = 180° 则:1弧度 = 180/π(°)
left_eye_x = result[0]
left_eye_y = result[1]
right_eye_x = result[2]
right_eye_y = result[3]
center = result[4]
# 现在获取角度
def getAngle(left_eye_x, left_eye_y, right_eye_x, right_eye_y):
dy = left_eye_y - right_eye_y
dx = left_eye_x - right_eye_x
angle = math.atan(dy/dx)*180/math.pi
return angle
angle = getAngle(left_eye_x, left_eye_y, right_eye_x, right_eye_y)
# 获得旋转矩阵
warp_matrix = cv2.getRotationMatrix2D(center, angle, 1)
# 最终得到旋转图像
rotated = cv2.warpAffine(img_, warp_matrix, (img.shape[1], img.shape[0]))