Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
vardanagarwal
GitHub Repository: vardanagarwal/Proctoring-AI
Path: blob/master/face_landmarks.py
453 views
1
# -*- coding: utf-8 -*-
2
"""
3
Created on Wed Jul 29 19:47:08 2020
4
5
@author: hp
6
"""
7
8
import cv2
9
import numpy as np
10
import tensorflow as tf
11
from tensorflow import keras
12
13
14
def get_landmark_model(saved_model='models/pose_model'):
15
"""
16
Get the facial landmark model.
17
Original repository: https://github.com/yinguobing/cnn-facial-landmark
18
19
Parameters
20
----------
21
saved_model : string, optional
22
Path to facial landmarks model. The default is 'models/pose_model'.
23
24
Returns
25
-------
26
model : Tensorflow model
27
Facial landmarks model
28
29
"""
30
#model = keras.models.load_model(saved_model)
31
model = tf.saved_model.load(saved_model)
32
return model
33
34
def get_square_box(box):
35
"""Get a square box out of the given box, by expanding it."""
36
left_x = box[0]
37
top_y = box[1]
38
right_x = box[2]
39
bottom_y = box[3]
40
41
box_width = right_x - left_x
42
box_height = bottom_y - top_y
43
44
# Check if box is already a square. If not, make it a square.
45
diff = box_height - box_width
46
delta = int(abs(diff) / 2)
47
48
if diff == 0: # Already a square.
49
return box
50
elif diff > 0: # Height > width, a slim box.
51
left_x -= delta
52
right_x += delta
53
if diff % 2 == 1:
54
right_x += 1
55
else: # Width > height, a short box.
56
top_y -= delta
57
bottom_y += delta
58
if diff % 2 == 1:
59
bottom_y += 1
60
61
# Make sure box is always square.
62
assert ((right_x - left_x) == (bottom_y - top_y)), 'Box is not square.'
63
64
return [left_x, top_y, right_x, bottom_y]
65
66
def move_box(box, offset):
67
"""Move the box to direction specified by vector offset"""
68
left_x = box[0] + offset[0]
69
top_y = box[1] + offset[1]
70
right_x = box[2] + offset[0]
71
bottom_y = box[3] + offset[1]
72
return [left_x, top_y, right_x, bottom_y]
73
74
def detect_marks(img, model, face):
75
"""
76
Find the facial landmarks in an image from the faces
77
78
Parameters
79
----------
80
img : np.uint8
81
The image in which landmarks are to be found
82
model : Tensorflow model
83
Loaded facial landmark model
84
face : list
85
Face coordinates (x, y, x1, y1) in which the landmarks are to be found
86
87
Returns
88
-------
89
marks : numpy array
90
facial landmark points
91
92
"""
93
94
offset_y = int(abs((face[3] - face[1]) * 0.1))
95
box_moved = move_box(face, [0, offset_y])
96
facebox = get_square_box(box_moved)
97
98
h, w = img.shape[:2]
99
if facebox[0] < 0:
100
facebox[0] = 0
101
if facebox[1] < 0:
102
facebox[1] = 0
103
if facebox[2] > w:
104
facebox[2] = w
105
if facebox[3] > h:
106
facebox[3] = h
107
108
face_img = img[facebox[1]: facebox[3],
109
facebox[0]: facebox[2]]
110
face_img = cv2.resize(face_img, (128, 128))
111
face_img = cv2.cvtColor(face_img, cv2.COLOR_BGR2RGB)
112
113
# # Actual detection.
114
predictions = model.signatures["predict"](
115
tf.constant([face_img], dtype=tf.uint8))
116
117
# Convert predictions to landmarks.
118
marks = np.array(predictions['output']).flatten()[:136]
119
marks = np.reshape(marks, (-1, 2))
120
121
marks *= (facebox[2] - facebox[0])
122
marks[:, 0] += facebox[0]
123
marks[:, 1] += facebox[1]
124
marks = marks.astype(np.uint)
125
126
return marks
127
128
def draw_marks(image, marks, color=(0, 255, 0)):
129
"""
130
Draw the facial landmarks on an image
131
132
Parameters
133
----------
134
image : np.uint8
135
Image on which landmarks are to be drawn.
136
marks : list or numpy array
137
Facial landmark points
138
color : tuple, optional
139
Color to which landmarks are to be drawn with. The default is (0, 255, 0).
140
141
Returns
142
-------
143
None.
144
145
"""
146
for mark in marks:
147
cv2.circle(image, (mark[0], mark[1]), 2, color, -1, cv2.LINE_AA)
148
149
150