In recent years, artificial intelligence (AI) has made significant strides in computer vision, particularly in tasks such as gender and age detection. These capabilities can be leveraged in various real-world applications, from enhancing customer experiences to enabling advanced security features. In this tutorial, we'll walk through building a real-time gender and age detection web application using Flask, TensorFlow, and OpenCV.
Introduction
The objective of this project is to develop a web application that can predict the gender and age range of a person from an image or live webcam feed. This application uses a pre-trained deep learning model to analyze the image and classify the individual's gender and age group. Flask serves as the web framework, facilitating interaction between the user and the AI model.
What You Will Learn
By following this tutorial, you will learn:
How to set up a Flask web application.
How to load and use a TensorFlow model for gender and age prediction.
How to capture real-time video feed using OpenCV and serve it through a web application.
How to handle image uploads and integrate predictions into a user-friendly interface.
Prerequisites
Before you begin, ensure you have the following:
Basic knowledge of Python programming.
TensorFlow installed in your environment (pip install tensorflow).
Flask installed (pip install flask).
OpenCV installed (pip install opencv-python).
Setting Up the Environment
First, make sure you have installed all the necessary libraries mentioned above. You can do this by running the following commands in your terminal:
pip install tensorflow flask opencv-python
These commands will install TensorFlow for AI model handling, Flask for the web framework, and OpenCV for video capture and image processing.
Understanding the Code
Let's break down the code into its core components to understand how the application works.
1. Importing Required Libraries
from flask import Flask, render_template, request, jsonify, Response
import time
import tensorflow as tf
import cv2
import numpy as np
Here, we import essential libraries:
flask: Used for creating the web interface and handling HTTP requests.
tensorflow: For loading and running the pre-trained gender and age detection model.
opencv-python: To capture video feed from the webcam and process images.
numpy: For handling numerical operations, particularly for image processing.
2. Initializing the Flask Application
app = Flask(__name__)
This line initializes the Flask application, creating an instance of the Flask class. This instance will handle all routing and serve the web pages.
3. Loading the Pre-Trained Model
model = tf.keras.models.load_model('a_g_best.h5')
The application loads a pre-trained TensorFlow model, which is stored in the a_g_best.h5 file. This model is designed to predict both gender and age range from an input image.
4. Creating a Class Dictionary
class_dict = {
'(0, 2)': 0,
'(4, 6)': 1,
'(8, 12)': 2,
'(15, 20)': 3,
'(25, 32)': 4,
'(27, 32)': 5,
'(38, 43)': 6,
'(38, 42)': 7,
'(48, 53)': 8,
'(60, 100)': 9,
}
This dictionary is used for mapping age ranges to specific class indices. This mapping is crucial when interpreting the model's predictions.
5. Injecting Timestamp into Templates
@app.context_processor
def inject_timestamp():
return {'timestamp': int(time.time())}
The inject_timestamp function injects a timestamp into the template context. This is useful for cache-busting static files such as CSS and JavaScript by appending a unique query parameter based on the current time.
6. Defining Flask Routes
a) Home Route:
@app.route('/')
def home():
return render_template('home.html')
This route renders the main page (home.html), where users can upload images or access the webcam for gender and age prediction.
b) Video Feed Route:
@app.route('/video_feed')
def video_feed():
return Response(generate_frames(), mimetype='multipart/x-mixed-replace; boundary=frame')
This route streams the webcam feed to the web page. The generate_frames function captures frames from the webcam and streams them as a continuous video feed.
7. Capturing and Streaming Video Frames
def generate_frames():
global last_frame
camera = cv2.VideoCapture(0)
while True:
success, frame = camera.read() # Read the camera frame
if not success:
break
else:
ret, buffer = cv2.imencode('.jpg', frame)
frame = buffer.tobytes()
last_frame = frame
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
This function continuously captures frames from the webcam, encodes them into JPEG format, and yields them for streaming to the client. OpenCV is used to interface with the webcam and capture frames in real time.
8. Preprocessing Images for Prediction
def preprocess_image(img):
img = tf.image.resize(img, (198, 198)) # Resize the image to the model's input size
img = tf.keras.applications.mobilenet_v2.preprocess_input(img)
img = tf.expand_dims(img, axis=0) # Add a batch dimension
return img
This function resizes the image to match the input dimensions expected by the model, normalizes the pixel values, and adds a batch dimension, making it ready for prediction.
9. Predicting Gender and Age
@app.route('/predict', methods=['POST', 'GET'])
def predict():
global last_frame, model
img = request.files.get('file-upload')
if last_frame is not None:
nparr = np.frombuffer(last_frame, np.uint8)
img_np = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
img_np = preprocess_image(img_np)
age_pred, gender_pred = model.predict(img_np)
xx = list(age_pred[0])
max_i = -1
count = 0
for i in age_pred[0]:
if i > max_i:
max_i = i
temp = count
count += 1
if temp == 0:
age = '0-24 yrs old'
elif temp == 1:
age = '25-49 yrs old'
elif temp == 2:
age = '50-74 yrs old'
elif temp == 3:
age = '75-99 yrs old'
elif temp == 4:
age = '91-124 yrs old'
if gender_pred[0][0] > gender_pred[0][1]:
gender = 'male'
else:
gender = 'female'
last_frame, nparr, img_np = None, None, None
return render_template('prediction.html', predictions=[gender, age])
elif img is None:
img = request.files['file-upload']
img = preprocess_image(img)
age_pred, gender_pred = model.predict(img)
xx = list(age_pred[0])
max_i = -1
count = 0
for i in age_pred[0]:
if i > max_i:
max_i = i
temp = count
count += 1
if temp == 0:
age = '0-24 yrs old'
elif temp == 1:
age = '25-49 yrs old'
elif temp == 2:
age = '50-74 yrs old'
elif temp == 3:
age = '75-99 yrs old'
elif temp == 4:
age = '91-124 yrs old'
if gender_pred[0][0] > gender_pred[0][1]:
gender = 'male'
else:
gender = 'female'
return render_template('prediction.html', predictions=[gender, age])
else:
return render_template('prediction.html', predictions=['No webcam or image was uploaded', 'Please upload and try again, Note: Do not refresh!'])
This route handles the prediction logic based on the latest captured video frame or uploaded image. It processes the image, makes predictions using the model, and renders the results on the prediction.html template.
Age Classification: The code snippet processes the model's predictions to determine the correct age range based on the highest probability.
Gender Prediction: The gender prediction is determined by comparing the probabilities for male and female.
10. Handling Image Uploads
@app.route('/predict_upload', methods=['POST'])
def predict_upload():
img = request.files['file-upload']
img = preprocess_image(img)
age_pred, gender_pred = model.predict(img)
xx = list(age_pred[0])
max_i = -1
count = 0
for i in age_pred[0]:
if i > max_i:
max_i = i
temp = count
count += 1
if temp == 0:
age = '0-24 yrs old'
elif temp == 1:
age = '25-49 yrs old'
elif temp == 2:
age = '50-74 yrs old'
elif temp == 3:
age = '75-99 yrs old'
elif temp == 4:
age = '91-124 yrs old'
if gender_pred[0][0] > gender_pred[0][1]:
gender = 'male'
else:
gender = 'female'
return render_template('prediction.html', predictions=[gender, age])
Building the User Interface
The application includes two HTML templates: home.html and prediction.html.
a) Home Page:
The home.html template provides a simple interface where users can either upload an image or use the webcam to capture a photo for prediction.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Gender and Age Detection</title>
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/styles_main.css') }}?v={{ timestamp }}">
</head>
<body>
<div class="main-heading">
<h1 style="text-align:center;">Gender and Age Detection App</h1>
</div>
<form action="/predict" method="POST" enctype="multipart/form-data" onsubmit="return false;">
<div class="button-container">
<button class="webcam-btn" id="webcam-btn" capture>Webcam</button>
<label for="file-upload" id="file-upload-label">Upload</label>
<input type="file" id="file-upload" name="file-upload">
</div>
<div class="image-container">
<img id="uploaded-image" class="hidden">
<video id="video" autoplay muted src="{{ url_for('video_feed') }}" class="hidden"></video>
</div>
<div class="button-container">
<button type="submit" id="submit-btn">Predict</button>
</div>
</form>
<script type="text/javascript" src="{{ url_for('static', filename='js/js_main.js') }}"></script>
</body>
</html>
This template contains a form where users can either upload an image or use the webcam to capture a live feed. The video feed is displayed if the webcam option is selected.
b) Prediction Page (prediction.html):
The prediction.html template displays the prediction results, showing the predicted gender and age range.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Prediction Results</title>
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/styles_main.css') }}?v={{ timestamp }}">
</head>
<body>
<div class="main-heading">
<h1 align="center">Gender and Age Detection Results</h1>
</div>
<div class="prediction-container">
{% if predictions %}
<p><strong>Gender:</strong> {{ predictions[0] }}</p>
{% endif %}
</div>
<div class="prediction-container">
{% if predictions %}
<p><strong>Age Range:</strong> {{ predictions[1] }}</p>
{% endif %}
</div>
<div class="button-container">
<a class="home-button" href="/">Go Back Home</a>
</div>
</body>
</html>
Running the Application
To run the application, save the code and HTML files in the same directory. Ensure your TensorFlow model (a_g_best.h5) is in the same directory. Then, execute the following command in your terminal:
python app.py
This will start the Flask server. Open your web browser and navigate to http://127.0.0.1:5000/ to access the web app.
Now you can we successfully built a real-time gender and age detection web application using Flask, TensorFlow, and OpenCV. This project demonstrates the powerful synergy between AI and web technologies, making advanced machine learning models accessible through a simple web interface.
Complete Code
app.py
from flask import Flask, render_template, request, jsonify, Response
import time
import tensorflow as tf
import cv2
import numpy as np
app = Flask(__name__)
last_frame = None
# final_age_class_map = {
# 0:'(0, 20)',
# 1:'(21, 40)',
# 2:'(41, 59)',
# 3:'(60, 100)'
# }
model = tf.keras.models.load_model('a_g_best.h5')
# age_model = tf.keras.models.load_model('age_model.h5')
# gender_model = tf.keras.models.load_model('gender_model.h5')
class_dict = {
'(0, 2)':0,
'(4, 6)':1,
'(8, 12)':2,
'(15, 20)':3,
'(25, 32)':4,
'(27, 32)':5,
'(38, 43)':6,
'(38, 42)':7,
'(48, 53)':8,
'(60, 100)':9,
}
@app.context_processor
def inject_timestamp():
return {'timestamp': int(time.time())}
@app.route('/')
def home():
return render_template('home.html')
def generate_frames():
global last_frame
camera = cv2.VideoCapture(0)
while True:
success, frame = camera.read() # read the camera frame
if not success:
break
else:
ret, buffer = cv2.imencode('.jpg', frame)
frame = buffer.tobytes()
last_frame = frame
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
@app.route('/video_feed')
def video_feed():
return Response(generate_frames(), mimetype='multipart/x-mixed-replace; boundary=frame')
def preprocess_image(img):
img = tf.image.resize(img, (198, 198)) # if gender_age_model then (224, 224)
img = tf.keras.applications.mobilenet_v2.preprocess_input(img)
img = tf.expand_dims(img, axis=0)
print(img.shape)
return img
@app.route('/predict', methods=['POST','GET'])
def predict():
global last_frame, final_age_class_map, model
img = request.files['file-upload']
if last_frame is not None:
nparr = np.frombuffer(last_frame, np.uint8)
img_np = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
img_np = preprocess_image(img_np)
# pred_age = age_model.predict(img_np)
# pred_gender = gender_model.predict(img_np)
# if np.argmax(pred_gender, axis=1) == 0:
# gender = 'Male'
# elif np.argmax(pred_gender, axis=1) == 1:
# gender = 'Female'
# else:
# gender = 'Model Not able to predict with good confidence'
# age = list(class_dict.keys())[list(class_dict.values()).index(np.argmax(pred_age, axis=1))]
age_pred, gender_pred = model.predict(img_np)
xx = list(age_pred[0])
max_i=-1
count=0
for i in age_pred[0]:
if i> max_i:
max_i = i
temp = count
count+=1
if temp==0:
age = '0-24 yrs old'
if temp==1:
age = '25-49 yrs old'
if temp==2:
age = '50-74 yrs old'
if temp==3:
age = '75-99 yrs old'
if temp==4:
age = '91-124 yrs old'
if gender_pred[0][0]>gender_pred[0][1]:
gender = 'male'
else:
gender = 'female'
last_frame, nparr, img_np = None, None, None
return render_template('prediction.html', predictions=[gender, age])
elif img == None:
img = request.files['file-upload']
img = preprocess_image(img)
# pred_age = age_model.predict(img)
# pred_gender = gender_model.predict(img)
# if np.argmax(pred_gender, axis=1) == 0:
# gender = 'Male'
# elif np.argmax(pred_gender, axis=1) == 1:
# gender = 'Female'
# else:
# gender = 'Model Not able to predict with good confidence'
# age = list(class_dict.keys())[list(class_dict.values()).index(np.argmax(pred_age, axis=1))]
age_pred, gender_pred = model.predict(img)
xx = list(age_pred[0])
max_i=-1
count=0
for i in age_pred[0]:
if i>max_i:
max_i = i
temp = count
count+=1
if temp==0:
age = '0-24 yrs old'
if temp==1:
age = '25-49 yrs old'
if temp==2:
age = '50-74 yrs old'
if temp==3:
age = '75-99 yrs old'
if temp==4:
age = '91-124 yrs old'
if gender_pred[0][0]>gender_pred[0][1]:
gender = 'male'
else:
gender = 'female'
return render_template('prediction.html', predictions=[gender, age])
else:
return render_template('prediction.html', predictions=['No webcam or image was uploaded', 'Please upload and try again, Note Do not refresh!'])
# pred = model.predict(img_np)
# if pred[0] > 0.5:
# gender = 'Male'
# else:
# gender = 'Female'
# age_check = tf.argmax(pred[1], axis=0)
# age = final_age_class_map[age_check.numpy()[0]]
# return render_template('prediction.html', predictions=[gender, age])
@app.route('/predict_upload', methods=['POST'])
def predict_upload():
img = request.files['file-upload']
img = preprocess_image(img)
# pred_age = age_model.predict(img)
# pred_gender = gender_model.predict(img)
# if np.argmax(pred_gender, axis=1) == 0:
# gender = 'Male'
# elif np.argmax(pred_gender, axis=1) == 1:
# gender = 'Female'
# else:
# gender = 'Model Not able to predict with good confidence'
age_pred, gender_pred = model.predict(img)
xx = list(age_pred[0])
max_i=-1
count=0
for i in age_pred[0]:
if i> max_i:
max_i = i
temp = count
count+=1
if temp==0:
age = '0-24 yrs old'
if temp==1:
age = '25-49 yrs old'
if temp==2:
age = '50-74 yrs old'
if temp==3:
age = '75-99 yrs old'
if temp==4:
age = '91-124 yrs old'
if gender_pred[0][0]>gender_pred[0][1]:
gender = 'male'
else:
gender = 'female'
# age = list(class_dict.keys())[list(class_dict.values()).index(np.argmax(pred_age, axis=1))]
return render_template('prediction.html', predictions=[gender, age])
# pred = model.predict(img)
# if pred[0] > 0.5:
# gender = 'Male'
# else:
# gender = 'Female'
# age_check = tf.argmax(pred[1], axis=0)
# age = final_age_class_map[age_check.numpy()[0]]
# return render_template('prediction.html', predictions=[gender, age])
# @app.route('/predict', methods=['POST'])
# def predict():
# # Code to process the image and run it through the model goes here
# return jsonify({'gender': gender_prediction, 'age': age_prediction})
if __name__ == '__main__':
app.run(debug=True)
home.html
<!DOCTYPE html>
<head>
<title>Gender and Age Detection</title>
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/styles_main.css') }}?v={{ timestamp }}">
</head>
<body>
<div class="main-heading">
<h1 style="text-align:center;">Gender and Age Detection app</h1>
</div>
<form action="/predict" method="POST" enctype="multipart/form-data" onsubmit="return false;">
<div class="button-container">
<button class="webcam-btn" id="webcam-btn" capture>Webcam</button>
<label for="file-upload" id="file-upload-label">Upload</label>
<input type="file" id="file-upload" name="file-upload">
</div>
<div class="image-container">
<img id="uploaded-image" class="hidden">
<video id="video" autoplay muted src="{{ url_for('video_feed') }}" class="hidden"></video>
</div>
<div class="button-container">
<button type="submit" id="submit-btn">Predict</button>
</div>
</form>
<script type="text/javascript" src="{{ url_for('static', filename='js/js_main.js') }}"></script>
</body>
prediction.html
<!DOCTYPE html>
<head>
<title>Gender and Age Detection</title>
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/styles_main.css') }}?v={{ timestamp }}">
</head>
<body>
<div class="main-heading">
<h1 align="center">Gender and Age Detection app</h1>
</div>
<div class="prediction-container">
{% if predictions %}
<p>The Gender is {{predictions[0]}} </br></p>
{% endif %}
</div>
<div class="prediction-container">
{% if predictions %}
<p>The Age is {{predictions[1]}}</p>
{% endif %}
</div>
<div class="button-container">
<a class="home-button" href="/">Go Back Home</a>
</div>
</body>
Project Demo Video
You can extend this project by adding more features such as facial recognition, emotion detection, or deploying the app to a cloud platform like Heroku or AWS. This foundational knowledge opens the door to countless possibilities in AI-driven web applications.
Happy coding!
For any assistance with building a Real-Time Gender and Age Detection Web Application using Flask and TensorFlow, feel free to contact us.
Comments