photo2cartoon / p2c /utils /face_detect.py
hylee's picture
init
eb7d2bb
raw
history blame
2.85 kB
import cv2
import math
import numpy as np
import face_alignment
class FaceDetect:
def __init__(self, device, detector):
# landmarks will be detected by face_alignment library. Set device = 'cuda' if use GPU.
self.fa = face_alignment.FaceAlignment(face_alignment.LandmarksType._2D, device=device, face_detector=detector)
def align(self, image):
landmarks = self.__get_max_face_landmarks(image)
if landmarks is None:
return None
else:
return self.__rotate(image, landmarks)
def __get_max_face_landmarks(self, image):
preds = self.fa.get_landmarks(image)
if preds is None:
return None
elif len(preds) == 1:
return preds[0]
else:
# find max face
areas = []
for pred in preds:
landmarks_top = np.min(pred[:, 1])
landmarks_bottom = np.max(pred[:, 1])
landmarks_left = np.min(pred[:, 0])
landmarks_right = np.max(pred[:, 0])
areas.append((landmarks_bottom - landmarks_top) * (landmarks_right - landmarks_left))
max_face_index = np.argmax(areas)
return preds[max_face_index]
@staticmethod
def __rotate(image, landmarks):
# rotation angle
left_eye_corner = landmarks[36]
right_eye_corner = landmarks[45]
radian = np.arctan((left_eye_corner[1] - right_eye_corner[1]) / (left_eye_corner[0] - right_eye_corner[0]))
# image size after rotating
height, width, _ = image.shape
cos = math.cos(radian)
sin = math.sin(radian)
new_w = int(width * abs(cos) + height * abs(sin))
new_h = int(width * abs(sin) + height * abs(cos))
# translation
Tx = new_w // 2 - width // 2
Ty = new_h // 2 - height // 2
# affine matrix
M = np.array([[cos, sin, (1 - cos) * width / 2. - sin * height / 2. + Tx],
[-sin, cos, sin * width / 2. + (1 - cos) * height / 2. + Ty]])
image_rotate = cv2.warpAffine(image, M, (new_w, new_h), borderValue=(255, 255, 255))
landmarks = np.concatenate([landmarks, np.ones((landmarks.shape[0], 1))], axis=1)
landmarks_rotate = np.dot(M, landmarks.T).T
return image_rotate, landmarks_rotate
if __name__ == '__main__':
img = cv2.cvtColor(cv2.imread('3989161_1.jpg'), cv2.COLOR_BGR2RGB)
fd = FaceDetect(device='cpu')
face_info = fd.align(img)
if face_info is not None:
image_align, landmarks_align = face_info
for i in range(landmarks_align.shape[0]):
cv2.circle(image_align, (int(landmarks_align[i][0]), int(landmarks_align[i][1])), 2, (255, 0, 0), -1)
cv2.imwrite('image_align.png', cv2.cvtColor(image_align, cv2.COLOR_RGB2BGR))