Estimates age and gender from any face in a photo, or from a live camera capture. Full-stack: a Python vision backend, and a plain HTML/CSS/JS frontend.
Python · Flask · OpenCV · TensorFlow · JavaScript
Three stages, in order:
1 · Detect — YuNet locates every face in the frame and returns five landmarks for each (eyes, nose, mouth corners). It ships inside OpenCV, weighs 340 KB, and runs in single-digit milliseconds on CPU.
2 · Align — each face is rotated so the eye axis is horizontal, then cropped with a 20% margin and resized to 224×224. Aligning first means a tilted head doesn't look like a different kind of image to the classifier.
3 · Classify — a MobileNetV2 backbone, fine-tuned on UTKFace, with two output heads: one regressing age as a number, one classifying gender.
RetinaFace is more accurate on hard cases — small, occluded, or extreme-angle faces — but runs at roughly one frame per second on CPU, which rules out live capture. MTCNN is slower than YuNet and less accurate. YuNet lands within a few points of RetinaFace-MobileNet on standard benchmarks while running around 100× faster, needs no extra dependency, and is small enough to commit to the repository.
For faces roughly facing a camera — the entire use case here — the accuracy difference does not show. Accuracy you cannot run in real time is not accuracy you have.
The training set is re-cropped with the same detector the app uses at inference, with the same margin. UTKFace ships pre-cropped, but by a different detector with different framing — training on those and predicting on YuNet crops would mean the model sees one distribution while learning and another in production. Accuracy drops, and nothing errors, so it is easy to miss.
git clone https://github.com/Charan1845/Age-and-Gender-Recognition.git
cd Age-and-Gender-Recognition
python -m venv .venv
.venv\Scripts\activate # Windows
# source .venv/bin/activate # macOS / Linux
pip install -r requirements.txt
python backend/app.pyThen open http://127.0.0.1:5000.
Requires Python 3.10–3.12 (TensorFlow has no build for 3.13+ yet).
The YuNet detector downloads itself on first run. The trained classifier is not committed — see below. Without it the app still runs and boxes faces, showing a banner to say classification is unavailable.
Open notebooks/train_age_gender.ipynb in Google Colab, set the runtime to a T4 GPU,
and run it top to bottom. It pulls UTKFace from Kaggle, re-crops every face with YuNet,
fine-tunes MobileNetV2 in two stages, and exports the model.
Put the downloaded age_gender_model.keras in models/ and restart the server. No code
changes — the backend looks for it on start-up.
Training is two-stage on purpose: the backbone is frozen while the new heads learn, then the top 40 layers are unfrozen at a 100× lower learning rate. Fine-tuning everything at full rate from the start destroys the pretrained ImageNet features.
backend/
app.py Flask routes, request handling, JSON responses
model.py detection, alignment, cropping, classification
frontend/
index.html markup only
css/
js/
api.js the only file that talks HTTP
camera.js getUserMedia, capture, permission errors
ui.js DOM rendering
main.js wiring
notebooks/
train_age_gender.ipynb
models/ YuNet + trained classifier (gitignored)
data/ UTKFace (gitignored)
| Method | Route | Purpose |
|---|---|---|
GET |
/ |
the app |
GET |
/api/health |
whether a classifier is loaded |
POST |
/api/predict |
image in — faces, predictions, annotated image out |
/api/predict accepts either a multipart file upload or JSON with a base64 data URI, so
the upload and camera paths share one endpoint.
The camera is read in the browser, not on the server. cv2.VideoCapture(0) reads
the machine running the code — fine on a laptop, useless once hosted, since a server has
no webcam. getUserMedia works in both.
Older faces are under-predicted. UTKFace skews young, so the regression head hedges toward the middle of the distribution: a 60-year-old may come back as mid-forties. Predictions are also clamped to 0–100, since a linear output head can otherwise return negative ages for faces unlike anything it trained on.
Infants are the weakest case for gender, which is expected — the features the model relies on are not developed yet.
Python · Flask · OpenCV · TensorFlow · MobileNetV2 · YuNet · UTKFace