Back to Projects

Project Overview

Traditional attendance systems — RFID cards, PIN codes, manual registers — are vulnerable to proxy attendance (one person marking for another). This project replaces them with a biometric face recognition system that simultaneously verifies identity and detects spoofing attempts in real time.

99.4%Recognition Accuracy
97.8%Anti-Spoof Accuracy
<200msInference Time
0%Proxy Attendance

Problem Statement

Proxy attendance is a widespread issue in institutions and workplaces. A colleague can swipe a card or enter a PIN on behalf of an absent person. Even early face recognition systems were fooled by simply holding a printed photo in front of the camera.

The solution needed to: (1) accurately identify faces, (2) detect if the face is real or a spoof (photo/screen/mask), and (3) run fast enough for a real-time attendance gate.

System Architecture

Camera Feed (OpenCV) Face Detection (MTCNN — Multi-task Cascaded CNN) ┌─────────────────────┬──────────────────────┐ │ Identity Branch │ Liveness Branch │ │ FaceNet (128-d │ LBP + SVM │ │ embeddings) + SVM │ texture classifier │ └─────────────────────┴──────────────────────┘ Decision: REAL + KNOWN → Mark Attendance in DB SPOOF → Reject + Alert UNKNOWN → Flag for Review SQLite Database → Streamlit Dashboard

Face Detection with MTCNN

MTCNN runs three cascaded networks (P-Net → R-Net → O-Net) to detect faces at multiple scales. It outputs bounding boxes and 5 facial landmarks (eyes, nose, mouth corners) used for alignment before embedding.

Python
from mtcnn import MTCNN
import cv2, numpy as np

detector = MTCNN()

def detect_and_align(frame):
    rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
    results = detector.detect_faces(rgb)
    faces = []
    for r in results:
        x, y, w, h = r['box']
        x, y = max(0, x), max(0, y)
        face = rgb[y:y+h, x:x+w]
        face = cv2.resize(face, (160, 160))  # FaceNet input size
        faces.append((face, r['box'], r['confidence']))
    return faces

Face Recognition with FaceNet

FaceNet maps face images to a 128-dimensional embedding space where same-person faces cluster together. We use cosine similarity against stored embeddings — a threshold of 0.6 gives the best precision/recall tradeoff on our dataset.

Python
from keras_facenet import FaceNet
from sklearn.svm import SVC
from sklearn.preprocessing import LabelEncoder
import pickle, numpy as np

embedder = FaceNet()

def get_embedding(face_img):
    face_img = face_img.astype('float32')
    mean, std = face_img.mean(), face_img.std()
    face_img = (face_img - mean) / std          # whitening
    samples = np.expand_dims(face_img, axis=0)
    return embedder.embeddings(samples)[0]      # 128-d vector

# Training the SVM classifier
X_embeds = [get_embedding(f) for f in face_images]
le = LabelEncoder()
y_encoded = le.fit_transform(labels)

clf = SVC(kernel='linear', probability=True, C=1.0)
clf.fit(X_embeds, y_encoded)
with open('face_classifier.pkl','wb') as f:
    pickle.dump((clf, le), f)

Anti-Spoofing with LBP

Local Binary Patterns (LBP) capture micro-texture differences between real skin and printed/screen surfaces. Real faces have irregular, 3D texture; photos are flat and uniform. LBP encodes each pixel relative to its 8 neighbours into a binary histogram.

Python
from skimage.feature import local_binary_pattern
from sklearn.svm import SVC
import numpy as np, cv2

def extract_lbp_features(face_gray, P=8, R=1):
    lbp = local_binary_pattern(face_gray, P, R, method='uniform')
    n_bins = P + 2
    hist, _ = np.histogram(lbp.ravel(), bins=n_bins,
                           range=(0, n_bins), density=True)
    return hist   # 10-dimensional feature vector

# Collect real & spoof samples, train SVM
X_lbp = [extract_lbp_features(cv2.cvtColor(f, cv2.COLOR_RGB2GRAY))
         for f in all_face_samples]
y_liveness = [1]*n_real + [0]*n_spoof   # 1=real, 0=spoof

spoof_clf = SVC(kernel='rbf', probability=True, C=10, gamma='scale')
spoof_clf.fit(X_lbp, y_liveness)

Results & Evaluation

Tested on 50 registered identities with 200 real and 200 spoof samples (printed photos, phone screens, and laptop screens):

99.4%Recognition Accuracy
97.8%Spoof Detection Rate
1.2%False Accept Rate
SQLiteAttendance Store

Key finding: LBP outperformed deep liveness detection models (MobileNet-based) in speed at only marginal accuracy cost — critical for real-time gate deployment on CPU-only hardware.

Tech Stack

  • Face Detection: MTCNN
  • Face Embedding: FaceNet (keras-facenet)
  • Identity Classifier: SVM (scikit-learn)
  • Liveness Detection: LBP + SVM
  • Camera Interface: OpenCV
  • Database: SQLite with pandas export
  • Dashboard: Streamlit (attendance reports, real-time feed)
FaceNetMTCNNLBP SVMOpenCVStreamlitSQLite