You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

lock.py 4.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. #!/usr/bin/env python
  2. import subprocess
  3. import threading
  4. import getpass
  5. import os
  6. import time
  7. class I3Locker:
  8. def run(self):
  9. self.proc = subprocess.Popen([ "mlock" ])
  10. code = self.proc.wait()
  11. if code == 0 or self.killed:
  12. return 0
  13. else:
  14. print("mlock exited with code "+str(code))
  15. return -1
  16. def kill(self):
  17. self.killed = True
  18. self.proc.terminate()
  19. class FaceLocker:
  20. def run(self):
  21. self.delay = 200
  22. self.dev = 2
  23. self.running = True
  24. self.waitingProc = None
  25. # Import here because it's sloow
  26. import numpy as np
  27. import face_recognition
  28. import cv2
  29. # Read all face files
  30. faces = []
  31. faceencs = []
  32. path = f"./faces/{getpass.getuser()}"
  33. paths = []
  34. for f in os.listdir(path):
  35. p = f"{path}/{f}"
  36. print(f"reading {p}")
  37. face = face_recognition.load_image_file(p)
  38. faces.append(face)
  39. encs = face_recognition.face_encodings(face)
  40. if len(encs) == 0:
  41. print("Warning: "+path+" has no face!")
  42. continue
  43. faceencs.append(encs[0])
  44. paths.append(p)
  45. # Wait here if we're on battery
  46. battery = "/sys/class/power_supply/BAT0"
  47. keyboard = "AT Translated Set 2 keyboard"
  48. key = 36
  49. bat = False
  50. with open(f"{battery}/status", "r") as f:
  51. s = f.read().strip()
  52. if s == "Discharging" or s == "Unknown":
  53. bat = True
  54. if bat:
  55. print("Waiting for enter before starting face recognition")
  56. self.waitForKey(keyboard, key)
  57. # Match faces, blocks until a match is found or we're killed
  58. self.runFaces(faceencs, paths, np, face_recognition, cv2)
  59. if self.matching or self.killed:
  60. return 0
  61. else:
  62. return -1
  63. def runFaces(self, faceencs, paths, np, face_recognition, cv2):
  64. self.matching = False
  65. cap = cv2.VideoCapture(self.dev)
  66. tacc = self.delay
  67. then = 0
  68. avg = 128
  69. while not self.matching and self.running:
  70. ret, frame = cap.read()
  71. mean = cv2.mean(frame)[0]
  72. avg = (avg + mean) / 2
  73. if mean < avg:
  74. continue
  75. # delay
  76. now = time.time() * 1000
  77. if tacc < self.delay:
  78. tacc += now - then
  79. then = now
  80. continue
  81. else:
  82. tacc = 0
  83. then = now
  84. scale = 1
  85. rgb_frame = cv2.cvtColor(frame, cv2.COLOR_GRAY2RGB)
  86. small_rgb_frame = cv2.resize(rgb_frame, (0, 0), fx=scale, fy=scale)
  87. framelocs = face_recognition.face_locations(small_rgb_frame)
  88. frameencs = face_recognition.face_encodings(small_rgb_frame, framelocs)
  89. # Loop through each face in this frame of video
  90. for (top, right, bottom, left), frameenc in zip(framelocs, frameencs):
  91. # See if the face is a match for the known face(s)
  92. dists = face_recognition.face_distance(faceencs, frameenc)
  93. dist = dists[0]
  94. distidx = 0
  95. for i, d in enumerate(dists):
  96. if d < dist:
  97. dist = d
  98. distidx = i
  99. print(f"Distance: {dist} ({paths[distidx]})")
  100. # If a match was found in known_face_encodings, just use the first one.
  101. if dist <= 0.4:
  102. self.matching = True
  103. def waitForKey(self, keyboard, key):
  104. self.waitingProc = subprocess.Popen(
  105. f"xinput test '{keyboard}' | grep --line-buffered 'key press {key}' | exit",
  106. shell=True)
  107. self.waitingProc.wait()
  108. def kill(self):
  109. self.killed = True
  110. self.running = False
  111. if self.waitingProc:
  112. self.waitingProc.terminate()
  113. lockers = [
  114. I3Locker(),
  115. FaceLocker(),
  116. ]
  117. def runLocker(locker):
  118. ret = locker.run()
  119. if ret == 0:
  120. print(locker.__class__.__name__+" unlocked.")
  121. for l in lockers:
  122. if l == locker:
  123. continue
  124. l.kill()
  125. else:
  126. print(locker.__class__.__name__+" failed.")
  127. threads = []
  128. for locker in lockers:
  129. th = threading.Thread(target=runLocker, args=(locker,))
  130. th.start()
  131. threads.append(th)
  132. for th in threads:
  133. th.join()