Skip to content

Commit c2b16d5

Browse files
committed
add age & gender detection combination tutorial
1 parent f4ad391 commit c2b16d5

File tree

10 files changed

+354
-0
lines changed

10 files changed

+354
-0
lines changed

Diff for: README.md

+1
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ This is a repository of all the tutorials of [The Python Code](https://www.thepy
6262
- [SIFT Feature Extraction using OpenCV in Python](https://www.thepythoncode.com/article/sift-feature-extraction-using-opencv-in-python). ([code](machine-learning/sift))
6363
- [Age Prediction using OpenCV in Python](https://www.thepythoncode.com/article/predict-age-using-opencv). ([code](machine-learning/face-age-prediction))
6464
- [Gender Detection using OpenCV in Python](https://www.thepythoncode.com/article/gender-detection-using-opencv-in-python). ([code](machine-learning/face-gender-detection))
65+
- [Age and Gender Detection using OpenCV in Python](https://www.thepythoncode.com/article/gender-and-age-detection-using-opencv-python). ([code](machine-learning/age-and-gender-detection))
6566
- [Building a Speech Emotion Recognizer using Scikit-learn](https://www.thepythoncode.com/article/building-a-speech-emotion-recognizer-using-sklearn). ([code](machine-learning/speech-emotion-recognition))
6667
- [How to Convert Speech to Text in Python](https://www.thepythoncode.com/article/using-speech-recognition-to-convert-speech-to-text-python). ([code](machine-learning/speech-recognition))
6768
- [Top 8 Python Libraries For Data Scientists and Machine Learning Engineers](https://www.thepythoncode.com/article/top-python-libraries-for-data-scientists).

Diff for: machine-learning/age-and-gender-detection/README.md

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# [Age and Gender Detection using OpenCV in Python](https://www.thepythoncode.com/article/gender-and-age-detection-using-opencv-python)
2+
To run this:
3+
- `pip3 install -r requirements.txt`
4+
- Check [the tutorial](https://www.thepythoncode.com/article/gender-and-age-detection-using-opencv-python) for more information on how to set this up.
5+
- After you download the models weights and architectures, you can perform age & gender detection on any image:
6+
```
7+
$ python age_and_gender_detection.py images/kids.jpg
8+
```
9+
- You can also use your camera, via the `age_and_gender_detection_live.py` script.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
# Import Libraries
2+
import cv2
3+
import numpy as np
4+
5+
# https://raw.githubusercontent.com/opencv/opencv/master/samples/dnn/face_detector/deploy.prototxt
6+
FACE_PROTO = "weights/deploy.prototxt.txt"
7+
# https://raw.githubusercontent.com/opencv/opencv_3rdparty/dnn_samples_face_detector_20180205_fp16/res10_300x300_ssd_iter_140000_fp16.caffemodel
8+
FACE_MODEL = "weights/res10_300x300_ssd_iter_140000_fp16.caffemodel"
9+
# The gender model architecture
10+
# https://drive.google.com/open?id=1W_moLzMlGiELyPxWiYQJ9KFaXroQ_NFQ
11+
GENDER_MODEL = 'weights/deploy_gender.prototxt'
12+
# The gender model pre-trained weights
13+
# https://drive.google.com/open?id=1AW3WduLk1haTVAxHOkVS_BEzel1WXQHP
14+
GENDER_PROTO = 'weights/gender_net.caffemodel'
15+
# Each Caffe Model impose the shape of the input image also image preprocessing is required like mean
16+
# substraction to eliminate the effect of illunination changes
17+
MODEL_MEAN_VALUES = (78.4263377603, 87.7689143744, 114.895847746)
18+
# Represent the gender classes
19+
GENDER_LIST = ['Male', 'Female']
20+
# The model architecture
21+
# download from: https://drive.google.com/open?id=1kiusFljZc9QfcIYdU2s7xrtWHTraHwmW
22+
AGE_MODEL = 'weights/deploy_age.prototxt'
23+
# The model pre-trained weights
24+
# download from: https://drive.google.com/open?id=1kWv0AjxGSN0g31OeJa02eBGM0R_jcjIl
25+
AGE_PROTO = 'weights/age_net.caffemodel'
26+
# Represent the 8 age classes of this CNN probability layer
27+
AGE_INTERVALS = ['(0, 2)', '(4, 6)', '(8, 12)', '(15, 20)',
28+
'(25, 32)', '(38, 43)', '(48, 53)', '(60, 100)']
29+
# Initialize frame size
30+
frame_width = 1280
31+
frame_height = 720
32+
# load face Caffe model
33+
face_net = cv2.dnn.readNetFromCaffe(FACE_PROTO, FACE_MODEL)
34+
# Load age prediction model
35+
age_net = cv2.dnn.readNetFromCaffe(AGE_MODEL, AGE_PROTO)
36+
# Load gender prediction model
37+
gender_net = cv2.dnn.readNetFromCaffe(GENDER_MODEL, GENDER_PROTO)
38+
39+
def get_faces(frame, confidence_threshold=0.5):
40+
# convert the frame into a blob to be ready for NN input
41+
blob = cv2.dnn.blobFromImage(frame, 1.0, (300, 300), (104, 177.0, 123.0))
42+
# set the image as input to the NN
43+
face_net.setInput(blob)
44+
# perform inference and get predictions
45+
output = np.squeeze(face_net.forward())
46+
# initialize the result list
47+
faces = []
48+
# Loop over the faces detected
49+
for i in range(output.shape[0]):
50+
confidence = output[i, 2]
51+
if confidence > confidence_threshold:
52+
box = output[i, 3:7] * \
53+
np.array([frame.shape[1], frame.shape[0],
54+
frame.shape[1], frame.shape[0]])
55+
# convert to integers
56+
start_x, start_y, end_x, end_y = box.astype(np.int)
57+
# widen the box a little
58+
start_x, start_y, end_x, end_y = start_x - \
59+
10, start_y - 10, end_x + 10, end_y + 10
60+
start_x = 0 if start_x < 0 else start_x
61+
start_y = 0 if start_y < 0 else start_y
62+
end_x = 0 if end_x < 0 else end_x
63+
end_y = 0 if end_y < 0 else end_y
64+
# append to our list
65+
faces.append((start_x, start_y, end_x, end_y))
66+
return faces
67+
68+
69+
def display_img(title, img):
70+
"""Displays an image on screen and maintains the output until the user presses a key"""
71+
# Display Image on screen
72+
cv2.imshow(title, img)
73+
# Mantain output until user presses a key
74+
cv2.waitKey(0)
75+
# Destroy windows when user presses a key
76+
cv2.destroyAllWindows()
77+
78+
79+
# from: https://stackoverflow.com/questions/44650888/resize-an-image-without-distortion-opencv
80+
def image_resize(image, width = None, height = None, inter = cv2.INTER_AREA):
81+
# initialize the dimensions of the image to be resized and
82+
# grab the image size
83+
dim = None
84+
(h, w) = image.shape[:2]
85+
# if both the width and height are None, then return the
86+
# original image
87+
if width is None and height is None:
88+
return image
89+
# check to see if the width is None
90+
if width is None:
91+
# calculate the ratio of the height and construct the
92+
# dimensions
93+
r = height / float(h)
94+
dim = (int(w * r), height)
95+
# otherwise, the height is None
96+
else:
97+
# calculate the ratio of the width and construct the
98+
# dimensions
99+
r = width / float(w)
100+
dim = (width, int(h * r))
101+
# resize the image
102+
return cv2.resize(image, dim, interpolation = inter)
103+
104+
105+
def get_gender_predictions(face_img):
106+
blob = cv2.dnn.blobFromImage(
107+
image=face_img, scalefactor=1.0, size=(227, 227),
108+
mean=MODEL_MEAN_VALUES, swapRB=False, crop=False
109+
)
110+
gender_net.setInput(blob)
111+
return gender_net.forward()
112+
113+
114+
def get_age_predictions(face_img):
115+
blob = cv2.dnn.blobFromImage(
116+
image=face_img, scalefactor=1.0, size=(227, 227),
117+
mean=MODEL_MEAN_VALUES, swapRB=False
118+
)
119+
age_net.setInput(blob)
120+
return age_net.forward()
121+
122+
123+
124+
def predict_age_and_gender(input_path: str):
125+
"""Predict the gender of the faces showing in the image"""
126+
# Initialize frame size
127+
# frame_width = 1280
128+
# frame_height = 720
129+
# Read Input Image
130+
img = cv2.imread(input_path)
131+
# resize the image, uncomment if you want to resize the image
132+
# img = cv2.resize(img, (frame_width, frame_height))
133+
# Take a copy of the initial image and resize it
134+
frame = img.copy()
135+
if frame.shape[1] > frame_width:
136+
frame = image_resize(frame, width=frame_width)
137+
# predict the faces
138+
faces = get_faces(frame)
139+
# Loop over the faces detected
140+
# for idx, face in enumerate(faces):
141+
for i, (start_x, start_y, end_x, end_y) in enumerate(faces):
142+
face_img = frame[start_y: end_y, start_x: end_x]
143+
age_preds = get_age_predictions(face_img)
144+
gender_preds = get_gender_predictions(face_img)
145+
i = gender_preds[0].argmax()
146+
gender = GENDER_LIST[i]
147+
gender_confidence_score = gender_preds[0][i]
148+
i = age_preds[0].argmax()
149+
age = AGE_INTERVALS[i]
150+
age_confidence_score = age_preds[0][i]
151+
# Draw the box
152+
label = f"{gender}-{gender_confidence_score*100:.1f}%, {age}-{age_confidence_score*100:.1f}%"
153+
# label = "{}-{:.2f}%".format(gender, gender_confidence_score*100)
154+
print(label)
155+
yPos = start_y - 15
156+
while yPos < 15:
157+
yPos += 15
158+
box_color = (255, 0, 0) if gender == "Male" else (147, 20, 255)
159+
cv2.rectangle(frame, (start_x, start_y), (end_x, end_y), box_color, 2)
160+
# Label processed image
161+
font_scale = 0.54
162+
cv2.putText(frame, label, (start_x, yPos),
163+
cv2.FONT_HERSHEY_SIMPLEX, font_scale, box_color, 2)
164+
165+
# Display processed image
166+
display_img("Gender Estimator", frame)
167+
# uncomment if you want to save the image
168+
cv2.imwrite("output.jpg", frame)
169+
# Cleanup
170+
cv2.destroyAllWindows()
171+
172+
173+
if __name__ == "__main__":
174+
import sys
175+
input_path = sys.argv[1]
176+
predict_age_and_gender(input_path)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
# Import Libraries
2+
import cv2
3+
import numpy as np
4+
5+
# The gender model architecture
6+
# https://drive.google.com/open?id=1W_moLzMlGiELyPxWiYQJ9KFaXroQ_NFQ
7+
GENDER_MODEL = 'weights/deploy_gender.prototxt'
8+
# The gender model pre-trained weights
9+
# https://drive.google.com/open?id=1AW3WduLk1haTVAxHOkVS_BEzel1WXQHP
10+
GENDER_PROTO = 'weights/gender_net.caffemodel'
11+
# Each Caffe Model impose the shape of the input image also image preprocessing is required like mean
12+
# substraction to eliminate the effect of illunination changes
13+
MODEL_MEAN_VALUES = (78.4263377603, 87.7689143744, 114.895847746)
14+
# Represent the gender classes
15+
GENDER_LIST = ['Male', 'Female']
16+
# https://raw.githubusercontent.com/opencv/opencv/master/samples/dnn/face_detector/deploy.prototxt
17+
FACE_PROTO = "weights/deploy.prototxt.txt"
18+
# https://raw.githubusercontent.com/opencv/opencv_3rdparty/dnn_samples_face_detector_20180205_fp16/res10_300x300_ssd_iter_140000_fp16.caffemodel
19+
FACE_MODEL = "weights/res10_300x300_ssd_iter_140000_fp16.caffemodel"
20+
# The model architecture
21+
# download from: https://drive.google.com/open?id=1kiusFljZc9QfcIYdU2s7xrtWHTraHwmW
22+
AGE_MODEL = 'weights/deploy_age.prototxt'
23+
# The model pre-trained weights
24+
# download from: https://drive.google.com/open?id=1kWv0AjxGSN0g31OeJa02eBGM0R_jcjIl
25+
AGE_PROTO = 'weights/age_net.caffemodel'
26+
# Represent the 8 age classes of this CNN probability layer
27+
AGE_INTERVALS = ['(0, 2)', '(4, 6)', '(8, 12)', '(15, 20)',
28+
'(25, 32)', '(38, 43)', '(48, 53)', '(60, 100)']
29+
# Initialize frame size
30+
frame_width = 1280
31+
frame_height = 720
32+
# load face Caffe model
33+
face_net = cv2.dnn.readNetFromCaffe(FACE_PROTO, FACE_MODEL)
34+
# Load age prediction model
35+
age_net = cv2.dnn.readNetFromCaffe(AGE_MODEL, AGE_PROTO)
36+
# Load gender prediction model
37+
gender_net = cv2.dnn.readNetFromCaffe(GENDER_MODEL, GENDER_PROTO)
38+
39+
def get_faces(frame, confidence_threshold=0.5):
40+
# convert the frame into a blob to be ready for NN input
41+
blob = cv2.dnn.blobFromImage(frame, 1.0, (300, 300), (104, 177.0, 123.0))
42+
# set the image as input to the NN
43+
face_net.setInput(blob)
44+
# perform inference and get predictions
45+
output = np.squeeze(face_net.forward())
46+
# initialize the result list
47+
faces = []
48+
# Loop over the faces detected
49+
for i in range(output.shape[0]):
50+
confidence = output[i, 2]
51+
if confidence > confidence_threshold:
52+
box = output[i, 3:7] * \
53+
np.array([frame.shape[1], frame.shape[0],
54+
frame.shape[1], frame.shape[0]])
55+
# convert to integers
56+
start_x, start_y, end_x, end_y = box.astype(np.int)
57+
# widen the box a little
58+
start_x, start_y, end_x, end_y = start_x - \
59+
10, start_y - 10, end_x + 10, end_y + 10
60+
start_x = 0 if start_x < 0 else start_x
61+
start_y = 0 if start_y < 0 else start_y
62+
end_x = 0 if end_x < 0 else end_x
63+
end_y = 0 if end_y < 0 else end_y
64+
# append to our list
65+
faces.append((start_x, start_y, end_x, end_y))
66+
return faces
67+
68+
69+
# from: https://stackoverflow.com/questions/44650888/resize-an-image-without-distortion-opencv
70+
def image_resize(image, width = None, height = None, inter = cv2.INTER_AREA):
71+
# initialize the dimensions of the image to be resized and
72+
# grab the image size
73+
dim = None
74+
(h, w) = image.shape[:2]
75+
# if both the width and height are None, then return the
76+
# original image
77+
if width is None and height is None:
78+
return image
79+
# check to see if the width is None
80+
if width is None:
81+
# calculate the ratio of the height and construct the
82+
# dimensions
83+
r = height / float(h)
84+
dim = (int(w * r), height)
85+
# otherwise, the height is None
86+
else:
87+
# calculate the ratio of the width and construct the
88+
# dimensions
89+
r = width / float(w)
90+
dim = (width, int(h * r))
91+
# resize the image
92+
return cv2.resize(image, dim, interpolation = inter)
93+
94+
95+
def get_gender_predictions(face_img):
96+
blob = cv2.dnn.blobFromImage(
97+
image=face_img, scalefactor=1.0, size=(227, 227),
98+
mean=MODEL_MEAN_VALUES, swapRB=False, crop=False
99+
)
100+
gender_net.setInput(blob)
101+
return gender_net.forward()
102+
103+
104+
def get_age_predictions(face_img):
105+
blob = cv2.dnn.blobFromImage(
106+
image=face_img, scalefactor=1.0, size=(227, 227),
107+
mean=MODEL_MEAN_VALUES, swapRB=False
108+
)
109+
age_net.setInput(blob)
110+
return age_net.forward()
111+
112+
113+
114+
def predict_age_and_gender():
115+
"""Predict the gender of the faces showing in the image"""
116+
# create a new cam object
117+
cap = cv2.VideoCapture(0)
118+
119+
while True:
120+
_, img = cap.read()
121+
# Take a copy of the initial image and resize it
122+
frame = img.copy()
123+
# resize if higher than frame_width
124+
if frame.shape[1] > frame_width:
125+
frame = image_resize(frame, width=frame_width)
126+
# predict the faces
127+
faces = get_faces(frame)
128+
# Loop over the faces detected
129+
# for idx, face in enumerate(faces):
130+
for i, (start_x, start_y, end_x, end_y) in enumerate(faces):
131+
face_img = frame[start_y: end_y, start_x: end_x]
132+
# predict age
133+
age_preds = get_age_predictions(face_img)
134+
# predict gender
135+
gender_preds = get_gender_predictions(face_img)
136+
i = gender_preds[0].argmax()
137+
gender = GENDER_LIST[i]
138+
gender_confidence_score = gender_preds[0][i]
139+
i = age_preds[0].argmax()
140+
age = AGE_INTERVALS[i]
141+
age_confidence_score = age_preds[0][i]
142+
# Draw the box
143+
label = f"{gender}-{gender_confidence_score*100:.1f}%, {age}-{age_confidence_score*100:.1f}%"
144+
# label = "{}-{:.2f}%".format(gender, gender_confidence_score*100)
145+
print(label)
146+
yPos = start_y - 15
147+
while yPos < 15:
148+
yPos += 15
149+
box_color = (255, 0, 0) if gender == "Male" else (147, 20, 255)
150+
cv2.rectangle(frame, (start_x, start_y), (end_x, end_y), box_color, 2)
151+
# Label processed image
152+
cv2.putText(frame, label, (start_x, yPos),
153+
cv2.FONT_HERSHEY_SIMPLEX, 0.54, box_color, 2)
154+
155+
# Display processed image
156+
cv2.imshow("Gender Estimator", frame)
157+
if cv2.waitKey(1) == ord("q"):
158+
break
159+
# uncomment if you want to save the image
160+
# cv2.imwrite("output.jpg", frame)
161+
# Cleanup
162+
cv2.destroyAllWindows()
163+
164+
165+
if __name__ == "__main__":
166+
predict_age_and_gender()
Loading
1.56 MB
Loading
113 KB
Loading
25.7 KB
Loading
77.8 KB
Loading
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
opencv-python
2+
numpy

0 commit comments

Comments
 (0)