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

Share this project:

Updates

Submission history