I built Guardian because I wanted my laptop to be smart enough to defend my screen when I step away, and let me control my workspace without having to frantically reach for the keyboard every time someone walks behind me. It lives silently in the Windows system tray as a background daemon, monitoring my webcam feed for specific hand gestures and unfamiliar faces.
The first major engineering nightmare I hit was Windows hardware device contention. I had multiple independent threads—one running MediaPipe landmark analysis for gesture navigation, one polling facial embeddings, and one listening for panic triggers. Initially, each module tried to instantiate its own cv2.VideoCapture(0) stream. On Windows, that immediately triggered device lockouts (0x800705AA), dropped frames, or crashed the Python runtime entirely. To fix it, I designed a thread-safe SharedCamera singleton in guardian/modules/camera.py. A dedicated background reader thread captures raw frames behind a mutex lock (threading.Lock()), downscales the resolution to 640×480, and caps the stream at ~20 FPS. Every downstream module simply polls cam.get_frame() from shared memory, slashing CPU utilization from a scorching 95% down to barely noticeable background levels.
For facial recognition, I originally experimented with generic face recognition wrappers, but they were sluggish and prone to false rejections in varying room lighting. I rebuilt modules/face_lock.py using DeepFace with the FaceNet model backend and OpenCV Haar-cascade face detection. When initialized, Guardian loads reference embeddings from a serialized local pickle file (face_data.pkl) and computes the vector cosine distance against current faces: dist = 1 - (np.dot(a, b) / (norm(a) * norm(b))). If an unrecognized face stays in front of the camera past tolerance = 0.55 for more than blackout_seconds = 20, Guardian escalates to lockdown. It spawns a Tkinter daemon window configured with -fullscreen, -topmost, overrideredirect(True), and a pure black canvas, completely obscuring the OS desktop. To prevent accidentally locking myself out if lighting dips or an exception occurs, I implemented a fail-open architecture: pressing F12 instantly destroys the blackout overlay and arms a 15-second grace re-verification window (_rearm).
The hand gesture engine in modules/gesture.py uses MediaPipe Hands with a strict confidence debounce filter:
- Open Hand (
OPEN_HAND): All four fingertip landmarks extend above their PIP joints for 8 consecutive frames, triggeringpyautogui.hotkey("alt", "tab")with a 1.5-second cooldown. - Closed Fist (
FIST): All four fingertips curl below their PIP joints, firingpyautogui.hotkey("shift", "alt", "tab")to cycle windows backward. - The "OK" Decoy Trigger (
modules/window_closer.py): When the Euclidean distance between thumb tip (lm[4]) and index tip (lm[8]) drops below0.07while the middle, ring, and pinky fingers stay extended, Guardian instantly sendsAlt+F4to kill the active foreground window, pauses 300ms, and launches a preconfigured decoy URL (https://www.google.com) in the default browser viawebbrowser.open().
With system tray minimization via pystray and Pillow, the entire suite runs completely invisibly until you actually need it.