EyeGuard 20-20-20 ποΈ
A robust computer-vision application that enforces the 20-20-20 rule for eye health β with anti-spoofing protection against one-eye-closed tricks.
The 20-20-20 Rule
- Every 20 minutes of screen time
- Look at something 20 feet away
- For at least 20 seconds
Features
Core Functionality
- Real-time webcam eye tracking using MediaPipe Face Mesh (468 landmarks)
- Per-eye EAR (Eye Aspect Ratio) calculation β each eye tracked independently
- 20-minute timer with visual countdown
- 20-second rest enforcement β both eyes must stay closed
- Blink filtering β brief blinks (< 0.5s) don't count as rest
Anti-Spoofing / Anti-Cheating
- One-eye-closed trick = DETECTED β requires BOTH eyes closed simultaneously for the full 20 seconds
- Face disappearance detection β if the face leaves the camera during rest, the rest attempt fails
- Hysteresis thresholds β prevents flickering between open/closed states
- Temporal smoothing β median filter over 5 frames for stable EAR readings
- Geometric verification β uses facial landmark geometry, not just single-frame classification
State Machine
- SCREENING β Normal work, counting down 20 minutes
- ALERT β Time for a break! Flashing red banner asks user to close both eyes
- RESTING β Both eyes confirmed closed, counting 20 seconds
- REST_COMPLETE β Break finished successfully, timer resets
- SPOOFING β One-eye trick detected! 3-second penalty before retry
- NO_FACE β Face not visible, waiting for user
Requirements
pip install opencv-python-headless mediapipe==0.10.13 numpy
Usage
Basic Usage (default webcam)
python eye_guard_2020.py
Different Camera
python eye_guard_2020.py --camera 1
Adjust Sensitivity
python eye_guard_2020.py --ear-open 0.18 --ear-closed 0.12
Key Controls (during runtime)
qβ Quitrβ Reset the 20-minute timertβ Test mode (force alert immediately)
How It Works
Eye Aspect Ratio (EAR)
EAR = (||P2-P6|| + ||P3-P5||) / (2 * ||P1-P4||)
Open eye: EAR β 0.25β0.35
Closed eye: EAR β 0.05β0.15
Hysteresis
- Eye is closed only when EAR drops below
ear_closed(default 0.18) - Eye is open only when EAR rises above
ear_open(default 0.22) - This 0.04 gap provides stable state transitions
Blink Rejection
A closure must last at least 15 consecutive frames (~0.5s at 30fps) to count as "resting". Normal blinks (100β300ms) are filtered out.
One-Eye Trick Detection
During RESTING, if either eye re-opens while the other stays closed:
- Status immediately switches to SPOOFING
- The rest attempt is marked as failed
- A 3-second penalty is enforced
- The user must start the 20-second rest over
Testing
python test_eyeguard_synthetic.py
Tests cover:
- β Normal rest cycle (both eyes closed)
- β Spoofing detection (one eye closed)
- β Blink filtering (brief closures ignored)
- β Rest interruption (early opening)
- β No-face detection during rest
- β One-eye trick during alert phase
Why This Approach?
Our geometric approach cannot be fooled by closing one eye because it computes EAR for each eye independently and enforces an AND gate β both must be closed. This is fundamentally more robust than deep-learning classifiers that operate on whole-face images and can be confused by partial closures.
Parameters
| Parameter | Default | Description |
|---|---|---|
ear_open |
0.22 | EAR threshold to mark eye as open |
ear_closed |
0.18 | EAR threshold to mark eye as closed |
SCREEN_TIME_ALERT_SECONDS |
1200 | 20 minutes in seconds |
REST_DURATION_SECONDS |
20 | Rest duration in seconds |
MIN_CONSECUTIVE_CLOSED_FRAMES |
15 | Minimum frames (~0.5s) to count as rest start |
License
MIT β free for personal and commercial use. Protect your eyes! π
Generated by ML Intern
This model repository was generated by ML Intern, an agent for machine learning research and development on the Hugging Face Hub.
- Try ML Intern: https://smolagents-ml-intern.hf.space
- Source code: https://github.com/huggingface/ml-intern