-
Notifications
You must be signed in to change notification settings - Fork 38
/
Copy pathencode_faces.py
150 lines (122 loc) · 4.59 KB
/
encode_faces.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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
'''
Find faces in given images and encode into 128-D embeddings.
Usage:
$ python3 encode_faces.py --dataset dataset --encodings encodings.pickle
Part of the smart-zoneminder project:
See https://github.com/goruck/smart-zoneminder.
Copyright (c) 2018~2020 Lindo St. Angel
'''
import face_recognition
import argparse
import pickle
import cv2
from os.path import sep
from glob import glob
# Height and / or width to resize all faces to.
FACE_HEIGHT = None
FACE_WIDTH = None
# Jitters for dlib.
NUM_JITTERS = 500
# Alternative labling of images.
USE_ALT = False
ALT_SUBFOLDER = 'no_faces'
ALT_LABEL = 'Unknown'
print('\n quantifying faces...')
# Construct the argument parser and parse the arguments.
ap = argparse.ArgumentParser()
ap.add_argument('-i', '--dataset', required=True,
help='path to input directory of faces + images')
ap.add_argument('-e', '--encodings', required=True,
help='name of serialized output file of facial encodings')
ap.add_argument('-d', '--detection-method', type=str, default='cnn',
help='face detection model to use: either `hog` or `cnn`')
args = vars(ap.parse_args())
def image_resize(image, width = None, height = None, inter = cv2.INTER_AREA):
# ref: https://stackoverflow.com/questions/44650888/resize-an-image-without-distortion-opencv
# initialize the dimensions of the image to be resized and
# grab the image size
dim = None
(h, w) = image.shape[:2]
# if both the width and height are None, then return the
# original image
if width is None and height is None:
return image
# check to see if the width is None
if width is None:
# calculate the ratio of the height and construct the
# dimensions
r = height / float(h)
dim = (int(w * r), height)
# otherwise, the height is None
else:
# calculate the ratio of the width and construct the
# dimensions
r = width / float(w)
dim = (width, int(h * r))
# resize the image
resized = cv2.resize(image, dim, interpolation = inter)
# return the resized image
return resized
# Grab the paths to the input images in our dataset.
imagePaths = glob(args['dataset'] + '/**/*.*', recursive=True)
# Initialize the list of known encodings and known names
knownEncodings = []
knownNames = []
# Loop over the image paths.
# NB: Its assumed that only one face is in each image.
not_encoded = 0
encoded = 0
for (i, imagePath) in enumerate(imagePaths):
print('processing image {}/{}'.format(i + 1, len(imagePaths)))
# Extract the person name from the image path.
name = imagePath.split(sep)[-2]
# if alt subfolder name is found...
if name == ALT_SUBFOLDER:
if USE_ALT: # ...label as alt
name = ALT_LABEL
else: # ...label as parent folder name
name = imagePath.split(sep)[-3]
# Load the input image.
image = cv2.imread(imagePath)
# Resize image
# and convert it from BGR (OpenCV ordering)
# to dlib ordering (RGB).
resized = image_resize(image, height=FACE_HEIGHT, width=FACE_WIDTH)
rgb = cv2.cvtColor(resized, cv2.COLOR_BGR2RGB)
#(height, width) = rgb.shape[:2]
#print('face height {} width {}'.format(height, width))
#cv2.imwrite('./face_rgb.jpg', rgb)
# Detect the (x, y)-coordinates of the bounding boxes
# corresponding to each face in the input image.
# Do not increase upsample beyond 1 else you'll run out of memory.
# This is strictly not needed since its assumed the images are
# faces but it serves as a check for faces dlib can deal with.
boxes = face_recognition.face_locations(img=rgb,
number_of_times_to_upsample=1,
model=args['detection_method'])
if len(boxes) == 0:
print('\n *** no face found! ***')
print(' image {} \n'.format(imagePath))
not_encoded += 1
continue
# Compute the facial embedding for the face.
encoding = face_recognition.face_encodings(face_image=rgb,
known_face_locations=boxes,
num_jitters=NUM_JITTERS)[0]
#print(encoding)
if len(encoding) == 0:
print('\n *** no encoding! *** \n')
not_encoded += 1
continue
encoded += 1
# Add each encoding + name to set of known names and
# encodings.
knownEncodings.append(encoding)
knownNames.append(name)
print('\n faces encoded {} not encoded {} total {}'
.format(encoded, not_encoded, encoded+not_encoded))
# Dump the facial encodings + names to disk.
print('\n serializing encodings')
data = {'encodings': knownEncodings, 'names': knownNames}
with open(args['encodings'], 'wb') as outfile:
outfile.write(pickle.dumps(data))