-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathface.py
121 lines (106 loc) · 3.61 KB
/
face.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
import cv, cv2
import rectangle
from numpy import concatenate
import logging
class Face(object):
def __init__(self, config = {}):
self.config = {
"top_offset" : 1.0,
"bottom_offset" : 1.0,
"left_offset" : 0.0,
"right_offset" : 0.0,
"haar_confidence" : 3,
"min_face_size" : (70,70),
"cascade_frontal" : "cascades/haarcascade_frontalface_default.xml",
"cascade_profile" : "cascades/haarcascade_profileface.xml"
}
self.set_config(config)
# Create the cascades. We use both, a frontal- and a profile face cascade
self.cascade_frontal = cv2.CascadeClassifier(self.config["cascade_frontal"])
self.cascade_profile = cv2.CascadeClassifier(self.config["cascade_profile"])
# Initially, we have no valid face detection.
self.face_positions = []
# In order to improve perfomance,
# keep the face position for a couple of frames.
# Find face again after a certain number of frames.
self.face_delay = 100
# Count how many frames have passed,
# since we last did a face detection
self.frames_passed = 0
def positions(self, img):
"""
Get all faces in an image.
Also apply some padding to remove the area next to the faces.
This improves both, performance and robustness of the hand search.
"""
self.frames_passed += 1
# Speedup. Only redetect after a certain delay.
if self.faces_invalid():
self.recalculate(img)
return self.face_positions
def faces_invalid(self):
"""
Check if we can still use the old face positions or
if the delay is over and we need to find the face again in the image.
"""
if not self.face_positions:
# No previous face detection. Declare invalid.
return True
if self.frames_passed > self.face_delay:
# The delay has passed. Invalidate previous detection
return True
# Everything ok. We can use the old detection.
return False
def recalculate(self, img):
"""
Try to redetect the face position.
"""
logging.debug("Face detector: Scanning...")
# Reset the frame counter
self.frames_passed = 0
# Invalidate previous detections
self.face_positions = None
rects = self.detect(img)
for r in rects:
x1, y1, x2, y2 = r
logging.info("Face detector: Found face at %s", r)
if rects != None:
self.face_positions = rects
def detect(self, img):
"""
Find blobs which match a given HAAR cascade.
"""
#gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
#gray = cv2.equalizeHist(gray)
# Accumulate all detections in a list
r = self.detect_frontal(img) + self.detect_profile(img)
return r
def detect_frontal(self, img):
rects_frontal = self.cascade_frontal.detectMultiScale(img,
scaleFactor=1.1,
minNeighbors=self.config["haar_confidence"],
minSize=self.config["min_face_size"])
if len(rects_frontal) != 0:
# We found a frontal faces.
rects_frontal = rectangle.convert_from_wh(rects_frontal)
return rects_frontal.tolist()
else:
return []
def detect_profile(self, img):
# Detect faces turned sidewards
rects_profile = self.cascade_profile.detectMultiScale(img,
scaleFactor=1.2,
minNeighbors=self.config["haar_confidence"],
minSize=self.config["min_face_size"])
if len(rects_profile) != 0:
# OK, found profile faces.
rects_profile = rectangle.convert_from_wh(rects_profile)
return rects_profile.tolist()
else:
return []
def set_config(self, config):
"""
Load new settings at runtime
"""
for key in config:
self.config[key] = config[key]