Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

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