-
-
Real person: light code reflected, then a far head turn to the requested side. Verified in 19 s, analysed on AWS Lambda.
-
Phone video passed the light check but couldn't fake a 3D head turn twice, so it was referred to a human reviewer.
-
Phone photo held to the camera: it doesn't reflect the random light code, so LUMEN rejects it as not a live person.
Inspiration
Face checks now guard online exams, bank onboarding and account recovery, yet many can be fooled by a printed photo or a phone replaying someone's video. Commercial liveness tools often need depth or infrared cameras. I wanted to know whether an ordinary laptop webcam and screen could prove that a live, three-dimensional person is present, by challenging the face instead of just looking at it.
What it does
LUMEN runs a short verification session with two challenges:
- Light challenge: the screen flashes a random red/green/blue code. OpenCV 5 checks that the face reflects that exact code in time and colour. A recording or injected video cannot react to a code it has never seen.
- Head-turn challenge: a spoken prompt asks for a turn to a random side. On a real head the nose slides past the eyes; a flat photo or screen cannot do that.
The decision is Verified (both pass), Not a live person (code not reflected), or Referred to a human (still unsure after two attempts).
How I built it
- Laptop client (Python + OpenCV 5): YuNet face detection (
cv.FaceDetectorYN), full-screen challenges and spoken prompts. Only 48×48 face crops and 5 landmark points leave the device, never video. - AWS Lambda (Python 3.12): runs the OpenCV 5 analysis (per-pixel least-squares response to the light code, screen-to-camera lag search, skin masks in YCrCb, nose-shift tracking) and the decision policy. One structured log line per decision goes to CloudWatch. Nothing is stored.
- Deployment: one script run in AWS CloudShell builds OpenCV 5 for Lambda, stages it in S3, creates a log-only IAM role, and publishes a key-protected function URL.
Results
Evaluation used one webcam, one phone and two consenting participants, with all sessions analysed on AWS.
| Round | Real sessions verified | Phone attacks accepted |
|---|---|---|
| 1 (first policy) | 5 / 10 | 0 / 7 |
| 2 (final policy) | 9 / 10 | 1 / 11 |
Round 1 rejected real faces on a "3D relief" rule. I removed it using round-1 data, then recorded round 2 fresh. The one attack that got through, a bright phone swivelled hard, passed both checks by a thin margin. The report measures it and proposes the fix (raise the head-turn threshold from 0.60 to about 0.9; every real far turn so far scored 0.92 or more).
Challenges I ran into
- Remote pulse (rPPG) was too weak on a laptop webcam. Brightness flicker was larger than the pulse, so I kept it as a research tool, not a decision input.
- Paper reflects light like skin: a still printed photo passed the light challenge. That's why the head turn is mandatory.
- My first head-turn method failed against swivelled photos. Measuring a far turn fixed it.
- Webcam exposure control: locked exposure made frames too dark or too slow. Exposure is now locked only during the flashes and calibrated to keep the frame rate up.
- Amazon Bedrock quota was zero on my new account for the whole build, so the planned adaptive agent became future work.
What I learned
Two weak checks that cover each other's blind spots beat one clever check. I also learned that honest evaluation, with failure cases and disclosed threshold changes, matters more than a perfect-looking number.
What's next
A larger and more diverse evaluation (skin tones, glasses, masks, deepfakes), a browser client, and the measured fixes from the failure analysis.
Responsible use: no video is saved, flashes stay under 3 changes per second, and uncertain cases go to a human. Fairness across skin tones has not been measured yet.
Built With
- amazon-cloudwatch
- amazon-web-services
- aws-cloudshell
- aws-iam
- aws-lambda
- numpy
- opencv
- python
- scipy
- yunet
Log in or sign up for Devpost to join the conversation.