Created
February 23, 2020 17:45
-
-
Save by-sabbir/42bcdb5b1172d8859e0e181b29a9138b to your computer and use it in GitHub Desktop.
Medium Post The Math and Code Behind Facial Alignment
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#optionally you can draw roi box by calling draw_rect() helper function | |
def draw_rect(image, rect): | |
x, y = rect.tl_corner().x, rect.tl_corner().y | |
w, h = rect.width(), rect.height() | |
cv.rectangle(image, (x, y), (x + w, y + h), (0, 255, 0), 2) | |
# summing up with detecting face and drawing rectangle | |
faces = face_detector(frame, 0) | |
for face in faces: | |
draw_rect(frame, face) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import os | |
import dlib | |
base_dir = os.path.dirname(__file__) | |
# download the predictor file from http://dlib.net/files/shape_predictor_5_face_landmarks.dat.bz2 | |
shape_predictor_file = os.path.join(base_dir, "files", "shape_predictor_5_face_landmarks.dat") | |
face_detector = dlib.get_frontal_face_detector() | |
shape_predictor = dlib.shape_predictor(shape_predictor_file) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# helper function to compute angle and center of the line connecting eyes. | |
def get_angle(image, shape, type=5): | |
if type == 5: | |
shapes = np.array(shape.parts()) | |
left_eye = ((shapes[0].x + shapes[1].x) // 2, (shapes[0].y + shapes[1].y) // 2) | |
right_eye = ((shapes[2].x + shapes[3].x) // 2, (shapes[2].y + shapes[3].y) // 2) | |
nose = (shapes[4].x, shapes[4].y) | |
eye_center = ((left_eye[0] + right_eye[0]) // 2, (left_eye[1] + right_eye[1]) // 2) | |
cv.circle(image, left_eye, 2, COLOR["white"], -1) | |
cv.circle(image, right_eye, 2, COLOR["white"], -1) | |
cv.circle(image, nose, 2, COLOR["white"], -1) | |
cv.circle(image, eye_center, 5, COLOR["white"], -1) | |
cv.line(image, left_eye, right_eye, COLOR["blue"], 2) | |
cv.line(image, left_eye, nose, COLOR["blue"], 2) | |
cv.line(image, right_eye, nose, COLOR["blue"], 2) | |
# computing angle | |
dx = left_eye[0] - right_eye[0] | |
dy = left_eye[1] - right_eye[1] | |
angle = np.degrees(np.arctan2(dy, dx)) | |
cv.putText(image, str(int(abs(angle))) + " deg", (eye_center[0], eye_center[1] - 20), cv.FONT_HERSHEY_SIMPLEX, 0.6, COLOR["white"], 1) | |
return eye_center, angle | |
def align_img(image, center, angle): | |
height, width = image.shape[0], image.shape[1] | |
M = cv.getRotationMatrix2D(center, angle, 1) | |
return cv.warpAffine(image, M, (width, height)) | |
# for clearity we will copy&paste the whole code from shape_predictor.py | |
for face in faces: | |
draw_rect(frame, face) | |
# 5 points shape predictor spits out four cordinates of eyes and one for nose | |
points = shape_predictor(frame, face) | |
center, angle = get_angle(frame, points, type=5) | |
# final image by rotating the image we get the warped image | |
warped_img = align_img(unaligned, center, angle) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import cv2 as cv | |
source = 0 # replace 0 with any file with absolute path to analyze from video source | |
cap = cv.VideoCapture(source) | |
while True: | |
ret, frame = cap.read() | |
# skipping an empty frame | |
if not ret: | |
continue | |
# press 'esc' to exit the program | |
if cv.waitKey(10) & 0xff == 27: | |
break | |
# cleaning up | |
cap.release() | |
cv.destroyAllWindows() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# will continue from the previous dlib_face_detector.py line 10 | |
for face in faces: | |
draw_rect(frame, face) | |
# 5 points shape predictor spits out four cordinates of eyes and one for nose | |
points = shape_predictor(frame, face) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment