Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

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