|
import numpy
|
|
|
|
from .umeyama import umeyama
|
|
from numpy.linalg import inv
|
|
import cv2
|
|
|
|
mean_face_x = numpy.array([
|
|
0.000213256, 0.0752622, 0.18113, 0.29077, 0.393397, 0.586856, 0.689483, 0.799124,
|
|
0.904991, 0.98004, 0.490127, 0.490127, 0.490127, 0.490127, 0.36688, 0.426036,
|
|
0.490127, 0.554217, 0.613373, 0.121737, 0.187122, 0.265825, 0.334606, 0.260918,
|
|
0.182743, 0.645647, 0.714428, 0.793132, 0.858516, 0.79751, 0.719335, 0.254149,
|
|
0.340985, 0.428858, 0.490127, 0.551395, 0.639268, 0.726104, 0.642159, 0.556721,
|
|
0.490127, 0.423532, 0.338094, 0.290379, 0.428096, 0.490127, 0.552157, 0.689874,
|
|
0.553364, 0.490127, 0.42689 ])
|
|
|
|
mean_face_y = numpy.array([
|
|
0.106454, 0.038915, 0.0187482, 0.0344891, 0.0773906, 0.0773906, 0.0344891,
|
|
0.0187482, 0.038915, 0.106454, 0.203352, 0.307009, 0.409805, 0.515625, 0.587326,
|
|
0.609345, 0.628106, 0.609345, 0.587326, 0.216423, 0.178758, 0.179852, 0.231733,
|
|
0.245099, 0.244077, 0.231733, 0.179852, 0.178758, 0.216423, 0.244077, 0.245099,
|
|
0.780233, 0.745405, 0.727388, 0.742578, 0.727388, 0.745405, 0.780233, 0.864805,
|
|
0.902192, 0.909281, 0.902192, 0.864805, 0.784792, 0.778746, 0.785343, 0.778746,
|
|
0.784792, 0.824182, 0.831803, 0.824182 ])
|
|
|
|
landmarks_2D = numpy.stack( [ mean_face_x, mean_face_y ], axis=1 )
|
|
|
|
def get_align_mat(face, size, should_align_eyes):
|
|
mat_umeyama = umeyama(numpy.array(face.landmarks_as_xy()[17:]), landmarks_2D, True)[0:2]
|
|
|
|
if should_align_eyes is False:
|
|
return mat_umeyama
|
|
|
|
mat_umeyama = mat_umeyama * size
|
|
|
|
|
|
landmarks = numpy.matrix(face.landmarks_as_xy())
|
|
|
|
|
|
landmarks = numpy.expand_dims(landmarks, axis=1)
|
|
|
|
|
|
umeyama_landmarks = cv2.transform(landmarks, mat_umeyama, landmarks.shape)
|
|
|
|
|
|
mat_align_eyes = align_eyes(umeyama_landmarks, size)
|
|
|
|
|
|
|
|
mat_umeyama = numpy.matrix(mat_umeyama)
|
|
mat_umeyama.resize((3, 3))
|
|
mat_align_eyes = numpy.matrix(mat_align_eyes)
|
|
mat_align_eyes.resize((3, 3))
|
|
mat_umeyama[2] = mat_align_eyes[2] = [0, 0, 1]
|
|
|
|
|
|
transform_mat = mat_align_eyes * mat_umeyama
|
|
|
|
|
|
transform_mat = numpy.delete(transform_mat, 2, 0)
|
|
transform_mat = transform_mat / size
|
|
return transform_mat
|
|
|
|
|
|
from .face_blend import get_5_keypoint
|
|
|
|
def get_align_mat_new(src_lmk, tgt_lmk, size=256, should_align_eyes=False):
|
|
mat_umeyama = umeyama(get_5_keypoint(src_lmk), get_5_keypoint(tgt_lmk), True)[0:2]
|
|
|
|
|
|
if should_align_eyes is False:
|
|
return mat_umeyama
|
|
|
|
mat_umeyama = mat_umeyama * size
|
|
|
|
|
|
landmarks = numpy.matrix(face.landmarks_as_xy())
|
|
|
|
|
|
landmarks = numpy.expand_dims(landmarks, axis=1)
|
|
|
|
|
|
umeyama_landmarks = cv2.transform(landmarks, mat_umeyama, landmarks.shape)
|
|
|
|
|
|
mat_align_eyes = align_eyes(umeyama_landmarks, size)
|
|
|
|
|
|
|
|
mat_umeyama = numpy.matrix(mat_umeyama)
|
|
mat_umeyama.resize((3, 3))
|
|
mat_align_eyes = numpy.matrix(mat_align_eyes)
|
|
mat_align_eyes.resize((3, 3))
|
|
mat_umeyama[2] = mat_align_eyes[2] = [0, 0, 1]
|
|
|
|
|
|
transform_mat = mat_align_eyes * mat_umeyama
|
|
|
|
|
|
transform_mat = numpy.delete(transform_mat, 2, 0)
|
|
transform_mat = transform_mat / size
|
|
return transform_mat
|
|
|
|
|
|
"""
|
|
The MIT License (MIT)
|
|
|
|
Copyright (c) 2015-2016 Adrian Rosebrock, http://www.pyimagesearch.com
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
in the Software without restriction, including without limitation the rights
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
THE SOFTWARE.
|
|
"""
|
|
|
|
from collections import OrderedDict
|
|
import numpy as np
|
|
import cv2
|
|
|
|
|
|
|
|
FACIAL_LANDMARKS_IDXS = OrderedDict([
|
|
("mouth", (48, 68)),
|
|
("right_eyebrow", (17, 22)),
|
|
("left_eyebrow", (22, 27)),
|
|
("right_eye", (36, 42)),
|
|
("left_eye", (42, 48)),
|
|
("nose", (27, 36)),
|
|
("jaw", (0, 17)),
|
|
("chin", (8, 11))
|
|
])
|
|
|
|
|
|
|
|
def align_eyes(landmarks, size):
|
|
desiredLeftEye = (0.35, 0.35)
|
|
desiredFaceWidth = desiredFaceHeight = size
|
|
|
|
|
|
(lStart, lEnd) = FACIAL_LANDMARKS_IDXS["left_eye"]
|
|
(rStart, rEnd) = FACIAL_LANDMARKS_IDXS["right_eye"]
|
|
leftEyePts = landmarks[lStart:lEnd]
|
|
rightEyePts = landmarks[rStart:rEnd]
|
|
|
|
|
|
leftEyeCenter = leftEyePts.mean(axis=0).astype("int")
|
|
rightEyeCenter = rightEyePts.mean(axis=0).astype("int")
|
|
|
|
|
|
dY = rightEyeCenter[0,1] - leftEyeCenter[0,1]
|
|
dX = rightEyeCenter[0,0] - leftEyeCenter[0,0]
|
|
angle = np.degrees(np.arctan2(dY, dX)) - 180
|
|
|
|
|
|
|
|
eyesCenter = ((leftEyeCenter[0,0] + rightEyeCenter[0,0]) // 2, (leftEyeCenter[0,1] + rightEyeCenter[0,1]) // 2)
|
|
|
|
|
|
M = cv2.getRotationMatrix2D(eyesCenter, angle, 1.0)
|
|
|
|
return M |