diff --git a/.emilianaFeatureExtractor.py.kate-swp b/.emilianaFeatureExtractor.py.kate-swp deleted file mode 100644 index 72dbb6f..0000000 Binary files a/.emilianaFeatureExtractor.py.kate-swp and /dev/null differ diff --git a/emilianaFeatureExtractor.py b/emilianaFeatureExtractor.py index 3abc17b..1d9406e 100644 --- a/emilianaFeatureExtractor.py +++ b/emilianaFeatureExtractor.py @@ -1,22 +1,39 @@ import numpy as np +import time +import math +import emilianaFeature +def angle(p1, p2): + p1 = np.array(p1) + p2 = np.array(p2) + a = np.arctan2(*(p2 - p1)[::-1]) + return (a % (2 * np.pi)) + +def rotate(origin, point, a): + a = -a + ox, oy = origin + px, py = point + + qx = ox + math.cos(a) * (px - ox) - math.sin(a) * (py - oy) + qy = oy + math.sin(a) * (px - ox) + math.cos(a) * (py - oy) + return qx, qy class FeatureExtractor(): def __init__(self, max_feature_updates=0): - self.eye_l = Feature(max_feature_updates=max_feature_updates) - self.eye_r = Feature(max_feature_updates=max_feature_updates) - self.eyebrow_updown_l = Feature(max_feature_updates=max_feature_updates) - self.eyebrow_updown_r = Feature(max_feature_updates=max_feature_updates) - self.eyebrow_quirk_l = Feature(threshold=0.05, max_feature_updates=max_feature_updates) - self.eyebrow_quirk_r = Feature(threshold=0.05, max_feature_updates=max_feature_updates) - self.eyebrow_steepness_l = Feature(threshold=0.05, max_feature_updates=max_feature_updates) - self.eyebrow_steepness_r = Feature(threshold=0.05, max_feature_updates=max_feature_updates) - self.mouth_corner_updown_l = Feature(max_feature_updates=max_feature_updates) - self.mouth_corner_updown_r = Feature(max_feature_updates=max_feature_updates) - self.mouth_corner_inout_l = Feature(threshold=0.02, max_feature_updates=max_feature_updates) - self.mouth_corner_inout_r = Feature(threshold=0.02, max_feature_updates=max_feature_updates) - self.mouth_open = Feature(max_feature_updates=max_feature_updates) - self.mouth_wide = Feature(threshold=0.02, max_feature_updates=max_feature_updates) + self.eye_l = emilianaFeature.Feature(max_feature_updates=max_feature_updates) + self.eye_r = emilianaFeature.Feature(max_feature_updates=max_feature_updates) + self.eyebrow_updown_l = emilianaFeature.Feature(max_feature_updates=max_feature_updates) + self.eyebrow_updown_r = emilianaFeature.Feature(max_feature_updates=max_feature_updates) + self.eyebrow_quirk_l = emilianaFeature.Feature(threshold=0.05, max_feature_updates=max_feature_updates) + self.eyebrow_quirk_r = emilianaFeature.Feature(threshold=0.05, max_feature_updates=max_feature_updates) + self.eyebrow_steepness_l = emilianaFeature.Feature(threshold=0.05, max_feature_updates=max_feature_updates) + self.eyebrow_steepness_r = emilianaFeature.Feature(threshold=0.05, max_feature_updates=max_feature_updates) + self.mouth_corner_updown_l = emilianaFeature.Feature(max_feature_updates=max_feature_updates) + self.mouth_corner_updown_r = emilianaFeature.Feature(max_feature_updates=max_feature_updates) + self.mouth_corner_inout_l = emilianaFeature.Feature(threshold=0.02, max_feature_updates=max_feature_updates) + self.mouth_corner_inout_r = emilianaFeature.Feature(threshold=0.02, max_feature_updates=max_feature_updates) + self.mouth_open = emilianaFeature.Feature(max_feature_updates=max_feature_updates) + self.mouth_wide = emilianaFeature.Feature(threshold=0.02, max_feature_updates=max_feature_updates) def align_points(self, a, b, pts): a = tuple(a) diff --git a/face.py b/face.py index 2ac1e9b..6549c9a 100644 --- a/face.py +++ b/face.py @@ -1,9 +1,11 @@ import numpy as np import math import featureExtractor +import emilianaFeatureExtractor class FaceInfo(): - def __init__(self, id, tracker): + def __init__(self, id, tracker, featureType): + self.featureType = featureType self.id = id self.tracker = tracker self.face_3d = np.array([ @@ -100,7 +102,11 @@ class FaceInfo(): self.pts_3d = None self.eye_blink = None self.pnp_error = 0 - self.features = featureExtractor.FeatureExtractor() + if self.featureType == 0: + self.features = featureExtractor.FeatureExtractor() + else: + self.features = emilianaFeatureExtractor.FeatureExtractor() + self.current_features = {} self.contour = np.zeros((21,3)) self.update_contour() @@ -140,4 +146,6 @@ class FaceInfo(): self.pts_3d = self.normalize_pts3d(self.pts_3d) self.current_features = self.features.update(self.pts_3d[:, 0:2]) - self.eye_blink = [self.current_features["eye_r"],self.current_features["eye_l"] ] + self.eye_blink = [] + self.eye_blink.append(1 - min(max(0, -self.current_features["eye_r"]), 1)) + self.eye_blink.append(1 - min(max(0, -self.current_features["eye_l"]), 1)) diff --git a/facetracker.py b/facetracker.py index 8d322e3..62e8a24 100644 --- a/facetracker.py +++ b/facetracker.py @@ -31,6 +31,8 @@ parser.add_argument("-d", "--detection-threshold", type=float, help="Set minimum parser.add_argument("-s", "--silent", type=int, help="Set this to 1 to prevent text output on the console", default=0) parser.add_argument("--model", type=int, help="This can be used to select the tracking model. Higher numbers are models with better tracking quality, but slower speed, except for model 4, which is wink optimized.", default=3, choices=[0, 1, 2, 3, 4]) parser.add_argument("--preview", type=int, help="Preview the frames sent to the tracker", default=0) +parser.add_argument("--feature-type", type=int, help="Sets which version of feature extraction is used. 0 is my new version that works well for me and allows for some customization, 1 is EmilianaVT's version aka, normal OpenSeeFace operation", default=0, choices=[0, 1]) + args = parser.parse_args() @@ -48,6 +50,7 @@ height = args.height width = args.width previewFlag = (args.preview == 1) mirror_input = args.mirror_input +featureType = args.feature_type #I make a minor tweak to the framerate to help the camera out #it's an inpercetible amount of time per frame @@ -110,7 +113,7 @@ peak_camera_latency = 0.0 total_camera_latency = 0.0 failures = 0 -tracker = Tracker(width, height, messageQueue, threshold=args.threshold, silent=silent, model_type=args.model, detection_threshold=args.detection_threshold) +tracker = Tracker(width, height, messageQueue, featureType, threshold=args.threshold, silent=silent, model_type=args.model, detection_threshold=args.detection_threshold) #don't start until the webcam is ready while frameQueue.qsize() < 1: diff --git a/featureExtractor.py b/featureExtractor.py index f6507e3..19b4ffb 100644 --- a/featureExtractor.py +++ b/featureExtractor.py @@ -77,10 +77,10 @@ class FeatureExtractor(): f_pts = self.align_points(pts[42], pts[45], pts[[43, 44, 47, 46]]) f = (f_pts[0][1]/2 + f_pts[1][1]/2) - (f_pts[2][1]/2 + f_pts[3][1]/2) - features["eye_l"] = self.eye_l.update(f) + features["eye_l"] = -self.eye_l.update(f) f_pts = self.align_points(pts[36], pts[39], pts[[37, 38, 41, 40]]) f = (f_pts[0][1]/2 + f_pts[1][1]/2) - (f_pts[2][1]/2 + f_pts[3][1]/2) - features["eye_r"] = self.eye_r.update(f) + features["eye_r"] = -self.eye_r.update(f) f = ((pts[22][1]/2 + pts[26][1]/2) - (pts[42][1]/2 + pts[45][1]/2))/norm_distance_y features["eyebrow_updown_l"] = self.eyebrow_updown_l.update(f) diff --git a/tracker.py b/tracker.py index dcb5263..476262a 100644 --- a/tracker.py +++ b/tracker.py @@ -6,6 +6,7 @@ import eyes import landmarks import face import featureExtractor +import emilianaFeatureExtractor #this file is so much smaller than it used to be, lol @@ -33,12 +34,16 @@ def clamp_to_im(pt, w, h): #8 times per frame, but that only accounts for 0.005m return (int(x),int(y+1)) class Tracker(): - def __init__(self, width, height, messageQueue, model_type=3, detection_threshold=0.6, threshold=0.6, silent=False): + def __init__(self, width, height, messageQueue, featureType, model_type=3, detection_threshold=0.6, threshold=0.6, silent=False): self.FaceDetector = facedetection.FaceDetector(detection_threshold = detection_threshold) self.EyeTracker = eyes.EyeTracker() self.Landmarks = landmarks.Landmarks(width, height, model_type, threshold) - self.FeatureExtractor = featureExtractor.FeatureExtractor() + if featureType == 0: + self.FeatureExtractor = featureExtractor.FeatureExtractor() + else: + self.FeatureExtractor = emilianaFeatureExtractor.FeatureExtractor() + # Image normalization constants self.mean = np.float32(np.array([-2.1179, -2.0357, -1.8044])) @@ -52,7 +57,7 @@ class Tracker(): self.threshold = threshold self.faces = [] - self.face_info = [face.FaceInfo(0, self)] + self.face_info = [face.FaceInfo(0, self, featureType)] self.messageQueue = messageQueue def preprocess(self, im):