第二次迭代之人脸摆正
第二次迭代是要求在第一次迭代的基础上添加人脸摆正功能,而人脸摆正其实就是将图片中倾斜的人脸进行旋转摆正,以希望减少人脸截取后对下一部分的影响。
人脸摆正的简单方法就是计算角度然后旋转人脸,计算角度我们用到的是opencv里面的一个人眼分类器,根据分类器得到人眼的两个位置坐标点(x,y,w,h),然后我们可以取矩形位置的正中心为人眼位置,这样我们可以根据人眼位置得到坐标计算成直线,然后计算与水平位置的夹角,也就是利用arctan值来得到倾斜的角度;对于旋转摆正则需要用到numpy包内的矩阵处理函数,我们需要根据角度先计算旋转后图片大小,然后根据角度代入原图片(python内图片保存为矩阵形式),得到旋转矩阵,最后利用warpAffine函数传入原图、旋转矩阵、旋转后大小等得到旋转后的人脸图,最后可利用之前完成的人脸截取将摆正后的图截取下来,这就是一个完整的摆正过程。
代码如下:
import cv2
import numpy
import math
def rotate_about_center(src, angle, scale):#src表示图片,angle表示角度,scale表示放缩比例
w = src.shape[1]#得到宽
h = src.shape[0]#得到高
rangle = numpy.deg2rad(angle)#夹角处理为弧度
nw = (abs(numpy.sin(rangle)*h) + abs(numpy.cos(rangle)*w))*scale#新图片的宽高
nh = (abs(numpy.cos(rangle)*h) + abs(numpy.sin(rangle)*w))*scale
rot_mat = cv2.getRotationMatrix2D((nw*0.5, nh*0.5), angle, scale)#得到旋转矩阵
rot_move = numpy.dot(rot_mat, numpy.array([(nw-w)*0.5, (nh-h)*0.5,0]))#中心点的转移
rot_mat[0,2] += rot_move[0]
rot_mat[1,2] += rot_move[1]
return cv2.warpAffine(src, rot_mat, (int(math.ceil(nw)), int(math.ceil(nh))), flags=cv2.INTER_LANCZOS4)#旋转处理
def get_angle(frame):
face_cascade = cv2.CascadeClassifier("haarcascade_frontalface_alt2.xml")
eye_cascade = cv2.CascadeClassifier("haarcascade_eye_tree_eyeglasses.xml")
faces = face_cascade.detectMultiScale(frame)#检测人脸
angle = 0 #默认为0,表示不旋转
for (x, y, w, h) in faces:
roi_gray = frame[y:y + h, x:x + w]#人脸图
eyes = eye_cascade.detectMultiScale(roi_gray)#得到人眼坐标
x_eye = []
y_eye = []
for (ex, ey, ew, eh) in eyes:
x_eye.append((ex + ew) / 2)
y_eye.append((ey + eh) / 2)
if len(x_eye) == 2:
angle = math.atan((y_eye[1] - y_eye[0]) / (x_eye[1] - x_eye[0])) * 180 / math.pi#计算夹角
break#单张人脸检测
return angle
def get_face(frame):#截取人脸
face_cascade = cv2.CascadeClassifier("haarcascade_frontalface_alt2.xml")
faces = face_cascade.detectMultiScale(frame)
if len(faces) > 0:
imgROI = frame[faces[0][1]:faces[0][1] + faces[0][3], faces[0][0]:faces[0][0] + faces[0][2]] # 前者为高度,后者为宽度
imgROI = cv2.resize(imgROI, (256, 256), cv2.INTER_LINEAR) # 固定大小
return imgROI
frame = cv2.imread("1.jpg")
cv2.imshow("original",frame)
cv2.imshow("rotate",rotate_about_center(frame,get_angle(frame),1))
cv2.imshow("face",get_face(rotate_about_center(frame,get_angle(frame),1)))
cv2.waitKey()
然后根据代码我们可以运行得到结果:
可以看出对于图片的摆正效果还可以,但是摆正的前提基于能检测到人眼,这就对图片有着很多的限制,同时角度太大的话人脸摆正中的人脸分类器无法检测出人脸,也自然无法检测人眼,可以看出人眼摆正实际上确实有些不足,但对于该项目而言倾斜程度也应该不会很大,所以还是能使用到的。