-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathfacetracker.py
113 lines (98 loc) · 3.23 KB
/
facetracker.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
import os
import cv2
import numpy as np
from eventkit import Op
import heartwave.conf as conf
class FaceTracker(Op):
"""
Detect and track faces::
(frame) -> (frame, faces)
"""
def __init__(self, source=None):
Op.__init__(self, source)
path = os.path.join(
os.path.dirname(__file__),
'data', 'lbpcascade_frontalface_improved.xml')
self.classifier = cv2.CascadeClassifier(path)
self.trackers = []
self.t0 = 0.0
def on_source(self, frame):
t1, im = frame
for tracker in self.trackers:
tracker.update(t1, im)
self.trackers = [
t for t in self.trackers
if t1 - t.lastTrackTime < conf.FACE_TRACKING_TIMEOUT]
if t1 - self.t0 >= conf.FACE_DETECT_PAUSE:
gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
gray = cv2.equalizeHist(gray)
dets = self.classifier.detectMultiScale(
gray, scaleFactor=1.1, minNeighbors=5)
faces = [
self.scaleFace(x, y, w, h)
for (x, y, w, h) in dets]
for face in faces:
x, y, w, h = face
tracker = next(
(t for t in self.trackers if t.overlaps(face)), None)
if tracker:
weight = 0.2 if tracker.ok else 1
tracker.updateROI(t1, im, face, weight)
else:
tracker = Tracker(t1, im, face)
self.trackers.append(tracker)
self.t0 = t1
faces = [t.roi for t in self.trackers]
self.emit(frame, faces)
def scaleFace(self, x, y, w, h):
'''
Calculate whole face based on detected face coordinates.
'''
fx, fy, fw, fh = [0.5, 0.35, 1.0, 1.4]
rw = w * fw
rh = h * fh
rx = x + fx * w - rw / 2
ry = y + fy * h - rh / 2
face = np.array([rx, ry, rw, rh], 'd')
return face
class Tracker:
"""
Track a region of interest in a video.
"""
def __init__(self, t, im, roi):
self.roi = roi
self.updateROI(t, im, roi)
def updateROI(self, t, im, roi, weight=0.5):
"""
Set the new ROI as weighted average of the given ROI
(with given weight) and old ROI.
"""
self.lastTrackTime = self.lastRoiTime = t
self.roi += weight * (roi - self.roi)
self.tracker = cv2.TrackerMedianFlow.create()
self.tracker.init(im, tuple(self.roi))
self.ok = True
def update(self, t, im):
"""
Update ROI with new time and image.
"""
if self.ok:
self.ok, roi = self.tracker.update(im)
if self.ok:
self.roi = roi
self.lastTrackTime = t
def contains(self, x, y):
"""
Is point (x, y) is contained in the ROI?
"""
rx, ry, rw, rh = self.roi
return rx < x < rx + rw and ry < y < ry + rh
def overlaps(self, roi):
"""
Does the given ROI overlap current ROI?
"""
x0, y0, w0, h0 = self.roi
x1, y1, w1, h1 = roi
return (
x0 <= x1 + w1 and x1 <= x0 + w0 and
y0 <= y1 + h1 and y1 <= y0 + h0)