| @@ -0,0 +1 @@ | |||
| /faces | |||
| @@ -1,35 +0,0 @@ | |||
| #!/usr/bin/env python | |||
| # Lock with mlock, unlock when face is detected | |||
| import subprocess | |||
| import threading | |||
| locker = subprocess.Popen([ "mlock" ]) | |||
| print("locker "+str(locker.pid)+" spawned") | |||
| matcher = subprocess.Popen([ "./facewaiter.py" ]) | |||
| print("matcher "+str(matcher.pid)+" spawned") | |||
| def waitfor(x, others): | |||
| code = x.wait() | |||
| if code != 0: | |||
| print(str(x.pid)+" died with code "+str(code)+"!") | |||
| else: | |||
| print(str(x.pid)+" died.") | |||
| for other in others: | |||
| if other.poll() == None: | |||
| print("killing "+str(other.pid)) | |||
| other.terminate() | |||
| threads = [ | |||
| threading.Thread(target=waitfor, args=(locker, [ matcher ])), | |||
| threading.Thread(target=waitfor, args=(matcher, [ locker ])), | |||
| ] | |||
| for th in threads: | |||
| th.start() | |||
| for th in threads: | |||
| th.join() | |||
| subprocess.call([ "pkill", "i3lock" ]) | |||
| @@ -1,172 +0,0 @@ | |||
| #!/usr/bin/env python3 | |||
| # Match camera against existing faces, or record a new face. | |||
| import cv2 | |||
| import numpy as np | |||
| import face_recognition | |||
| import os | |||
| import time | |||
| import argparse | |||
| def match(paths, dev, show, delay, wait): | |||
| faces = [] | |||
| faceencs = [] | |||
| for path in paths: | |||
| print(f"reading {path}") | |||
| face = face_recognition.load_image_file(path) | |||
| faces.append(face) | |||
| encs = face_recognition.face_encodings(face) | |||
| if len(encs) == 0: | |||
| print("Warning: "+path+" has no face!") | |||
| continue | |||
| faceencs.append(encs[0]) | |||
| if len(faceencs) == 0: | |||
| print("Warning: No valid faces!") | |||
| if args.wait: | |||
| input("Waiting for newline...") | |||
| print("Got newline."); | |||
| cap = cv2.VideoCapture(dev) | |||
| matching = False | |||
| tacc = delay | |||
| then = 0 | |||
| avg = 128 | |||
| while not matching: | |||
| ret, frame = cap.read() | |||
| mean = cv2.mean(frame)[0] | |||
| avg = (avg + mean) / 2 | |||
| if mean < avg: | |||
| continue | |||
| # delay | |||
| now = time.time() * 1000 | |||
| if tacc < delay: | |||
| tacc += now - then | |||
| then = now | |||
| continue | |||
| else: | |||
| tacc = 0 | |||
| then = now | |||
| scale = 1 | |||
| rgb_frame = cv2.cvtColor(frame, cv2.COLOR_GRAY2RGB) | |||
| small_rgb_frame = cv2.resize(rgb_frame, (0, 0), fx=scale, fy=scale) | |||
| print("hey") | |||
| framelocs = face_recognition.face_locations(small_rgb_frame) | |||
| frameencs = face_recognition.face_encodings(small_rgb_frame, framelocs) | |||
| # Loop through each face in this frame of video | |||
| for (top, right, bottom, left), frameenc in zip(framelocs, frameencs): | |||
| # See if the face is a match for the known face(s) | |||
| dists = face_recognition.face_distance(faceencs, frameenc) | |||
| dist = dists[0] | |||
| distidx = 0 | |||
| for i, d in enumerate(dists): | |||
| if d < dist: | |||
| dist = d | |||
| distidx = i | |||
| print(f"Distance: {dist} ({paths[distidx]})") | |||
| if show: | |||
| cv2.rectangle( | |||
| rgb_frame, | |||
| (int(left / scale), int(top / scale)), | |||
| (int(right / scale), int(bottom / scale)), | |||
| (0, 0, 255), 2) | |||
| # If a match was found in known_face_encodings, just use the first one. | |||
| if dist <= 0.4: | |||
| matching = True | |||
| if show: | |||
| cv2.imshow("frame", rgb_frame) | |||
| if cv2.waitKey(1) & 0xFF == ord('q'): | |||
| break | |||
| # When everything done, release the capture | |||
| cap.release() | |||
| cv2.destroyAllWindows() | |||
| if matching: | |||
| print("Matches") | |||
| exit(0) | |||
| else: | |||
| exit(1) | |||
| def record(path, dev): | |||
| def draw_face_rec(name, frame): | |||
| rgb_frame = cv2.cvtColor(frame, cv2.COLOR_GRAY2RGB) | |||
| framelocs = face_recognition.face_locations(rgb_frame) | |||
| frameencs = face_recognition.face_encodings(rgb_frame, framelocs) | |||
| for (top, right, bottom, left), frameenc in zip(framelocs, frameencs): | |||
| cv2.rectangle(rgb_frame, (left, top), (right, bottom), (0, 0, 255), 2) | |||
| cv2.imshow(name, rgb_frame) | |||
| cap = cv2.VideoCapture(dev) | |||
| avg = 128 | |||
| while True: | |||
| ret, frame = cap.read() | |||
| mean = cv2.mean(frame)[0] | |||
| avg = (avg + mean) / 2 | |||
| if mean < avg: | |||
| continue | |||
| cv2.imshow("frame", frame) | |||
| key = cv2.waitKey(1) & 0xFF | |||
| if key == ord('q'): | |||
| break | |||
| elif key == ord('\r'): | |||
| cv2.imshow("frame", frame) | |||
| cv2.waitKey(1) | |||
| draw_face_rec("frame", frame) | |||
| while True: | |||
| key = cv2.waitKey(0) & 0xFF | |||
| if key == ord('\r'): | |||
| cv2.imwrite(path, frame) | |||
| return | |||
| elif key == 27: # esc | |||
| break | |||
| parser = argparse.ArgumentParser() | |||
| subs = parser.add_subparsers(dest="command", required=True) | |||
| sub_match = subs.add_parser("match") | |||
| sub_match.add_argument( | |||
| "-d", "--device", type=int, default=0, | |||
| help="the index of the video device") | |||
| sub_match.add_argument( | |||
| "-s", "--show", default=False, action="store_true", | |||
| help="show what the camera sees") | |||
| sub_match.add_argument( | |||
| "-w", "--wait", default=False, action="store_true", | |||
| help="wait for newline on stdin") | |||
| sub_match.add_argument( | |||
| "-t", "--delay", type=int, default=0, | |||
| help="wait n milliseconds between each frame") | |||
| sub_match.add_argument( | |||
| "faces", type=str, nargs="+", | |||
| help="the source image file(s)") | |||
| sub_record = subs.add_parser("record") | |||
| sub_record.add_argument( | |||
| "-d", "--device", type=int, default=0, | |||
| help="the index of the video device") | |||
| sub_record.add_argument( | |||
| "face", type=str, | |||
| help="the destination image file") | |||
| args = parser.parse_args() | |||
| if args.command == "match": | |||
| match(args.faces, args.device, args.show, args.delay, args.wait) | |||
| elif args.command == "record": | |||
| record(args.face, args.device) | |||
| @@ -1,32 +0,0 @@ | |||
| #!/usr/bin/env python | |||
| import subprocess | |||
| keyboard = "AT Translated Set 2 keyboard" | |||
| battery = "/sys/class/power_supply/BAT0" | |||
| device = "2" | |||
| faces = "faces" | |||
| key = "36" | |||
| bat = False | |||
| if battery is not None: | |||
| with open(f"{battery}/status", "r") as f: | |||
| s = f.read().strip() | |||
| if s == "Discharging" or s == "Unknown": | |||
| bat = True | |||
| print("starting facematcher") | |||
| proc = subprocess.Popen( | |||
| f"./facematcher.py match --wait --delay 500 --device {device} {faces}/$USER/*", | |||
| stdin=subprocess.PIPE, shell=True) | |||
| if bat: | |||
| print(f"On battery, so waiting for {key}") | |||
| subprocess.check_output( | |||
| f"xinput test '{keyboard}' | grep --line-buffered 'key press {key}' | exit", | |||
| shell=True) | |||
| print(f"Got {key}.") | |||
| proc.stdin.write(b"hello\n") | |||
| proc.stdin.flush() | |||
| exit(proc.wait()) | |||
| @@ -0,0 +1,155 @@ | |||
| #!/usr/bin/env python | |||
| import subprocess | |||
| import threading | |||
| import getpass | |||
| import os | |||
| import time | |||
| class I3Locker: | |||
| def run(self): | |||
| self.proc = subprocess.Popen([ "mlock" ]) | |||
| code = self.proc.wait() | |||
| if code == 0 or self.killed: | |||
| return 0 | |||
| else: | |||
| print("mlock exited with code "+str(code)) | |||
| return -1 | |||
| def kill(self): | |||
| self.killed = True | |||
| self.proc.terminate() | |||
| class FaceLocker: | |||
| def run(self): | |||
| self.delay = 200 | |||
| self.dev = 2 | |||
| self.running = True | |||
| self.waitingProc = None | |||
| # Import here because it's sloow | |||
| import numpy as np | |||
| import face_recognition | |||
| import cv2 | |||
| # Read all face files | |||
| faces = [] | |||
| faceencs = [] | |||
| path = f"./faces/{getpass.getuser()}" | |||
| paths = [] | |||
| for f in os.listdir(path): | |||
| p = f"{path}/{f}" | |||
| print(f"reading {p}") | |||
| face = face_recognition.load_image_file(p) | |||
| faces.append(face) | |||
| encs = face_recognition.face_encodings(face) | |||
| if len(encs) == 0: | |||
| print("Warning: "+path+" has no face!") | |||
| continue | |||
| faceencs.append(encs[0]) | |||
| paths.append(p) | |||
| # Wait here if we're on battery | |||
| battery = "/sys/class/power_supply/BAT0" | |||
| keyboard = "AT Translated Set 2 keyboard" | |||
| key = 36 | |||
| bat = False | |||
| with open(f"{battery}/status", "r") as f: | |||
| s = f.read().strip() | |||
| if s == "Discharging" or s == "Unknown": | |||
| bat = True | |||
| if bat: | |||
| print("Waiting for enter before starting face recognition") | |||
| self.waitForKey(keyboard, key) | |||
| # Match faces, blocks until a match is found or we're killed | |||
| self.runFaces(faceencs, paths, np, face_recognition, cv2) | |||
| if self.matching or self.killed: | |||
| return 0 | |||
| else: | |||
| return -1 | |||
| def runFaces(self, faceencs, paths, np, face_recognition, cv2): | |||
| self.matching = False | |||
| cap = cv2.VideoCapture(self.dev) | |||
| tacc = self.delay | |||
| then = 0 | |||
| avg = 128 | |||
| while not self.matching and self.running: | |||
| ret, frame = cap.read() | |||
| mean = cv2.mean(frame)[0] | |||
| avg = (avg + mean) / 2 | |||
| if mean < avg: | |||
| continue | |||
| # delay | |||
| now = time.time() * 1000 | |||
| if tacc < self.delay: | |||
| tacc += now - then | |||
| then = now | |||
| continue | |||
| else: | |||
| tacc = 0 | |||
| then = now | |||
| scale = 1 | |||
| rgb_frame = cv2.cvtColor(frame, cv2.COLOR_GRAY2RGB) | |||
| small_rgb_frame = cv2.resize(rgb_frame, (0, 0), fx=scale, fy=scale) | |||
| framelocs = face_recognition.face_locations(small_rgb_frame) | |||
| frameencs = face_recognition.face_encodings(small_rgb_frame, framelocs) | |||
| # Loop through each face in this frame of video | |||
| for (top, right, bottom, left), frameenc in zip(framelocs, frameencs): | |||
| # See if the face is a match for the known face(s) | |||
| dists = face_recognition.face_distance(faceencs, frameenc) | |||
| dist = dists[0] | |||
| distidx = 0 | |||
| for i, d in enumerate(dists): | |||
| if d < dist: | |||
| dist = d | |||
| distidx = i | |||
| print(f"Distance: {dist} ({paths[distidx]})") | |||
| # If a match was found in known_face_encodings, just use the first one. | |||
| if dist <= 0.4: | |||
| self.matching = True | |||
| def waitForKey(self, keyboard, key): | |||
| self.waitingProc = subprocess.Popen( | |||
| f"xinput test '{keyboard}' | grep --line-buffered 'key press {key}' | exit", | |||
| shell=True) | |||
| self.waitingProc.wait() | |||
| def kill(self): | |||
| self.killed = True | |||
| self.running = False | |||
| if self.waitingProc: | |||
| self.waitingProc.terminate() | |||
| lockers = [ | |||
| I3Locker(), | |||
| FaceLocker(), | |||
| ] | |||
| def runLocker(locker): | |||
| ret = locker.run() | |||
| if ret == 0: | |||
| print(locker.__class__.__name__+" unlocked.") | |||
| for l in lockers: | |||
| if l == locker: | |||
| continue | |||
| l.kill() | |||
| else: | |||
| print(locker.__class__.__name__+" failed.") | |||
| threads = [] | |||
| for locker in lockers: | |||
| th = threading.Thread(target=runLocker, args=(locker,)) | |||
| th.start() | |||
| threads.append(th) | |||
| for th in threads: | |||
| th.join() | |||
| @@ -0,0 +1,47 @@ | |||
| #!/usr/bin/env python | |||
| import sys | |||
| import cv2 | |||
| import numpy as np | |||
| import face_recognition | |||
| def record(path, dev): | |||
| def draw_face_rec(name, frame): | |||
| rgb_frame = cv2.cvtColor(frame, cv2.COLOR_GRAY2RGB) | |||
| framelocs = face_recognition.face_locations(rgb_frame) | |||
| frameencs = face_recognition.face_encodings(rgb_frame, framelocs) | |||
| for (top, right, bottom, left), frameenc in zip(framelocs, frameencs): | |||
| cv2.rectangle(rgb_frame, (left, top), (right, bottom), (0, 0, 255), 2) | |||
| cv2.imshow(name, rgb_frame) | |||
| cap = cv2.VideoCapture(dev) | |||
| avg = 128 | |||
| while True: | |||
| ret, frame = cap.read() | |||
| mean = cv2.mean(frame)[0] | |||
| avg = (avg + mean) / 2 | |||
| if mean < avg: | |||
| continue | |||
| cv2.imshow("frame", frame) | |||
| key = cv2.waitKey(1) & 0xFF | |||
| if key == ord('q'): | |||
| break | |||
| elif key == ord('\r'): | |||
| cv2.imshow("frame", frame) | |||
| cv2.waitKey(1) | |||
| draw_face_rec("frame", frame) | |||
| while True: | |||
| key = cv2.waitKey(0) & 0xFF | |||
| if key == ord('\r'): | |||
| cv2.imwrite(path, frame) | |||
| return | |||
| elif key == 27: # esc | |||
| break | |||
| if len(sys.argv) != 2: | |||
| print(f"Usage: {sys.argv[0]} <path>") | |||
| record(sys.argv[1], 2) | |||