-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlocator.py
121 lines (97 loc) · 3.85 KB
/
locator.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
"""
Locate face points
"""
import cv2
import numpy as np
import os.path as path
import dlib
import os
from imutils.face_utils import FaceAligner
from imutils.face_utils import rect_to_bb
import argparse
import imutils
import dlib
import cv2
dlib_detector = dlib.get_frontal_face_detector()
dlib_predictor = dlib.shape_predictor('./shape_predictor_68_face_landmarks.dat')
def boundary_points(points, width_percent=0.1, height_percent=0.1):
""" Produce additional boundary points
:param points: *m* x 2 array of x,y points
:param width_percent: [-1, 1] percentage of width to taper inwards. Negative for opposite direction
:param height_percent: [-1, 1] percentage of height to taper downwards. Negative for opposite direction
:returns: 2 additional points at the top corners
"""
x, y, w, h = cv2.boundingRect(np.array([points], np.int32))
spacerw = int(w * width_percent)
spacerh = int(h * height_percent)
return [[x+spacerw, y+spacerh],
[x+w-spacerw, y+spacerh]]
def face_points(img, size, add_boundary_points=True):
return face_points_dlib(img, size, add_boundary_points)
def face_points_dlib(img, size, add_boundary_points=True):
""" Locates 68 face points using dlib (http://dlib.net)
Requires shape_predictor_68_face_landmarks.dat to be in face_morpher/data
Download at: http://dlib.net/files/shape_predictor_68_face_landmarks.dat.bz2
:param img: an image array
:param add_boundary_points: bool to add additional boundary points
:returns: Array of x,y face points. Empty array if no face found
"""
try:
points = []
rgbimg = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
rects = dlib_detector(rgbimg, 1)
if rects and len(rects) > 0:
# We only take the first found face
shapes = dlib_predictor(rgbimg, rects[0])
points = np.array([(shapes.part(i).x, shapes.part(i).y) for i in range(68)], np.int32)
if add_boundary_points:
# Add more points inwards and upwards as dlib only detects up to eyebrows
points = np.vstack([
points,
boundary_points(points, 0.1, -0.03),
boundary_points(points, 0.13, -0.05),
boundary_points(points, 0.15, -0.08),
boundary_points(points, 0.33, -0.12)])
#print([[1,1],[(size[1]-2),1],[1,(size[0]-2)],[(size[1]-2),(size[0]-2)]])
points = np.vstack([points,[[10,10],[(size[1]-10),10],[10,(size[0]-10)],[(size[1]-10),(size[0]-10)]]])
return points
except Exception as e:
print(e)
return []
def face_points_stasm(img, add_boundary_points=True):
import stasm
""" Locates 77 face points using stasm (http://www.milbo.users.sonic.net/stasm)
:param img: an image array
:param add_boundary_points: bool to add 2 additional points
:returns: Array of x,y face points. Empty array if no face found
"""
try:
points = stasm.search_single(cv2.cvtColor(img, cv2.COLOR_BGR2GRAY))
except Exception as e:
print('Failed finding face points: ', e)
return []
points = points.astype(np.int32)
if len(points) == 0:
return points
if add_boundary_points:
return np.vstack([points, boundary_points(points)])
return points
def average_points(point_set):
""" Averages a set of face points from images
:param point_set: *n* x *m* x 2 array of face points. \\
*n* = number of images. *m* = number of face points per image
"""
return np.mean(point_set, 0).astype(np.int32)
def weighted_average_points(start_points, end_points, percent=0.5):
""" Weighted average of two sets of supplied points
:param start_points: *m* x 2 array of start face points.
:param end_points: *m* x 2 array of end face points.
:param percent: [0, 1] percentage weight on start_points
:returns: *m* x 2 array of weighted average points
"""
if percent <= 0:
return end_points
elif percent >= 1:
return start_points
else:
return np.asarray(start_points*percent + end_points*(1-percent), np.int32)