Source code for draugr.dlib_utilities.facealigner
import cv2
import numpy
from draugr.dlib_utilities.dlib_utilities import (
Dlib5faciallandmarksindices,
Dlib68faciallandmarksindices,
shape_to_ndarray,
)
from warg import Number
__all__ = ["align_face"]
[docs]def align_face(
image,
gray,
rect,
predictor,
desired_left_eye=(0.35, 0.35),
desired_face_size=None, # (256, 256),
padding: Number = 30,
debug: bool = False,
):
"""
:param padding:
:type padding:
:param debug:
:type debug:
:param image:
:param gray:
:param rect:
:param predictor:
:param desired_left_eye:
:param desired_face_size:
:return:
"""
if desired_face_size is not None:
desired_face_width, desired_face_height = desired_face_size
else:
desired_face_width, desired_face_height = (
rect.width() + padding * 2,
rect.height() + padding * 2,
) # BroadCastNone()
face_shape = shape_to_ndarray(predictor(gray, rect))
if len(face_shape) == 68:
slicer = Dlib68faciallandmarksindices
else:
slicer = Dlib5faciallandmarksindices
left_eye_pts = slicer.slice(face_shape, slicer.left_eye)
right_eye_pts = slicer.slice(face_shape, slicer.right_eye)
left_eye_center = left_eye_pts.mean(axis=0).astype(
numpy.int
) # compute the center of mass for each eye
right_eye_center = right_eye_pts.mean(axis=0).astype(numpy.int)
d_y = right_eye_center[1] - left_eye_center[1]
d_x = right_eye_center[0] - left_eye_center[0]
angle = (
numpy.degrees(numpy.arctan2(d_y, d_x)) - 180
).item() # compute the angle between the eye centroids
desired_right_eye_x = (
1.0 - desired_left_eye[0]
) # compute the desired right eye x-coordinate based on the desired x-coordinate of the left eye
# determine the scale of the new resulting image by taking
# the ratio of the distance between eyes in the *current*
# image to the ratio of distance between eyes in the
# *desired* image
dist = numpy.sqrt((d_x**2) + (d_y**2))
desired_dist = desired_right_eye_x - desired_left_eye[0]
desired_dist *= desired_face_width
scale = (desired_dist / dist).item()
eyes_center = (
((left_eye_center[0] + right_eye_center[0]) // 2).item(),
((left_eye_center[1] + right_eye_center[1]) // 2).item(),
) # compute center (x, y)-coordinates (i.e., the median point) between the two eyes in the input image
rot_m = cv2.getRotationMatrix2D(
eyes_center, angle, scale
) # grab the rotation matrix for rotating and scaling the face
t_x = desired_face_width * 0.5 # update the translation component of the matrix
t_y = desired_face_height * desired_left_eye[1]
rot_m[0, 2] += t_x - eyes_center[0]
rot_m[1, 2] += t_y - eyes_center[1]
return cv2.warpAffine(
image, rot_m, (desired_face_width, desired_face_height), flags=cv2.INTER_CUBIC
) # apply the affine transformation