Published September 9, 2020
Howdy! I saw a meme when I was in high school that was a picture of a man. Superimposed onto his bottom text was the phrase "This meme is a red square when you're not looking," the joke being that you wouldn't be able to see it if you weren't looking. Anyway, since then I've had this desire to really implement it, to make some kind of billboard/house sign that nonresidents wouldn't be able to see, perhaps to display the weekly dinner schedule or WiFi password.
Using a Raspberry Pi, raspicam, and downloading dlib's face recognition models, we were able to get it to run at 0.5 FPS. When someone it recognized from the "VIP Faces" folder was in view of the camera, it would turn the screen back on. Otherwise, the Raspberry Pi would black out the screen using some display power management functions invoked from the command.
This FPS is a little useless since it can't black out the screen fast enough, so I ported it over to my Mac. Here, it runs at \~10 FPS, so it can feasibly block out someone trying to view your screen. Another benefit is it blacks out the screen while you aren't looking at it (since it can't see your face), saving power (Assuming the display turn off and turn on don't cost any extra energy, which they probably do). Anyway, it only took a few hours to write, so here's all the code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | import face_recognition import cv2 import subprocess as sp import os import glob import numpy as np from functools import reduce # Start webcam stream video_capture = cv2.VideoCapture(0) # Load approved users known_face_encodings = dict() rootdir = os.path.dirname(__file__) + "/faces/" for fl in os.listdir(rootdir) : if fl.endswith(".jpg") or fl.endswith(".jpeg") or fl.endswith(".png") : image = face_recognition.load_image_file(rootdir + fl) known_face_encodings[fl] = face_recognition.face_encodings(image)[0] known_face_encodings = list(known_face_encodings.values()) # Initialize some variables new_face_locations = [] new_face_encodings = [] turned_off = False print('Starting privacy screen') while True: # Grab a single frame of video ret, frame = video_capture.read() # Resize frame of video to 1/4 size for faster face recognition processing small_frame = cv2.resize(frame, (0, 0), fx=0.2, fy=0.2) # Convert the image from BGR color (which OpenCV uses) to RGB color (which face_recognition uses) rgb_small_frame = small_frame[:, :, ::-1] # Find all the faces and face encodings in the current frame of video new_face_locations = face_recognition.face_locations(rgb_small_frame) new_face_encodings = face_recognition.face_encodings(rgb_small_frame, new_face_locations) matched = True # Loop over each face found in the frame to see if it's someone we know. for new_face_encoding in new_face_encodings: match = face_recognition.compare_faces(known_face_encodings, new_face_encoding) matched = matched and bool(sum(match)) matched = matched and (len(new_face_locations) > 0) # Make sure someone's there # Depending on the state of matched, toggle the screen on or off if not matched: # sp.run(["xset","dpms","force","off"]) # Debian, for Raspi sp.run(["pmset", "displaysleepnow"]) # MacOS turned_off = True elif turned_off: turned_off = False # sp.run(["xset","dpms","force","on"]) # Debian, for Raspi sp.run(["caffeinate", "-u", "-t", "1"]) # MacOS, has to run twice to be reliable sp.run(["caffeinate", "-u", "-t", "1"]) |
That's all! Pretty simple program, but taught me some stuff about display power management and the trickiness of installing dlib. Also, writing this post taught me about HTML formatting (hilite.me is kinda nice)