-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy pathtrain.py
114 lines (89 loc) · 3.66 KB
/
train.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
import os
from os.path import join, isdir
import cv2
import numpy as np
from detect import detect_faces, level_face
import config
def train_recognizer(db_folder, train_size=config.DEFAULT_FACE_SIZE, show_faces=False, force_train=False):
""" Train and return face recognier.
db_folder -- the image folder that group faces in sub-folders
train_size -- tuple of x and y size for resizing faces found before training
show_faces -- display images of faces found and used for training
force_train -- force re-training even when previous training result is found
"""
# recognizer = cv2.face.LBPHFaceRecognizer_create()
recognizer = cv2.face.FisherFaceRecognizer_create()
# recognizer = cv2.face.EigenFaceRecognizer_create()
if (not force_train) and _load_recognizer(recognizer):
return recognizer
folders = _get_labels(db_folder)
images = []
labels = []
label_count = 0
label_map = {}
for folder in folders:
faces = _extract_faces(db_folder, folder, True)
# resize all faces to same size for some recognizers
images.extend([cv2.resize(face, train_size) for face in faces])
labels.extend([label_count] * len(faces))
label_map[label_count] = folder
label_count += 1
if show_faces:
cv2.namedWindow("faces", 1)
cv2.imshow("faces", _combine_faces(faces))
print("Press any key to continue...")
cv2.waitKey(0)
if show_faces:
cv2.destroyWindow("faces")
recognizer.train(images, np.array(labels))
for key in label_map:
recognizer.setLabelInfo(key, label_map[key])
_save_recognizer(recognizer)
return recognizer
def _get_labels(a_dir):
return [name for name in os.listdir(a_dir) if isdir(join(a_dir, name))]
def _supported_img(name):
return name.lower().endswith('.png') or name.lower().endswith('.jpg') or name.lower().endswith('.jpeg')
def _combine_faces(faces, w=100, h=100, num_per_row=5):
small_img = []
row_img = []
count = 0
for img in faces:
small_img.append(cv2.resize(img, (w, h)))
count += 1
if count % num_per_row == 0:
count = 0
row_img.append(np.concatenate(small_img, axis=1))
small_img = []
if len(small_img) > 0:
for x in range (0, num_per_row-len(small_img)):
small_img.append(np.zeros((h,w), np.uint8))
row_img.append(np.concatenate(small_img, axis=1))
return np.concatenate(row_img, axis=0)
def _extract_faces(a_dir, folder, do_level_face=False):
faceCascade = cv2.CascadeClassifier(config.FACE_CASCADE_FILE)
eyeCascade = cv2.CascadeClassifier(config.EYE_CASCADE_FILE)
the_path = join(a_dir, folder)
result = []
for img in [f for f in os.listdir(the_path) if _supported_img(f)]:
img_path = join(the_path, img)
image, faces = detect_faces(cv2.imread(img_path), faceCascade, eyeCascade, True)
if len(faces) == 0:
print("No face found in " + img_path)
for ((x, y, w, h), eyedim) in faces:
if not do_level_face:
result.append(image[y:y+h, x:x+w])
else:
result.append(level_face(image, ((x, y, w, h), eyedim)))
#result.append(image[y:y+h, x:x+w])
return result
def _save_recognizer(recognizer, filename=config.RECOGNIZER_OUTPUT_FILE):
recognizer.save(filename)
def _load_recognizer(recognizer, filename=config.RECOGNIZER_OUTPUT_FILE):
try:
recognizer.read(filename)
return True
except (cv2.error):
return False
if __name__ == '__main__':
recognizer = train_recognizer('imgdb', show_faces=True, force_train=True)