/faces |
#!/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" ]) |
#!/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) |
#!/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()) |
#!/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() |
#!/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) |