Skip to content

Commit f4ad391

Browse files
committed
update age detection tutorial
1 parent 4e8197b commit f4ad391

File tree

2 files changed

+214
-30
lines changed

2 files changed

+214
-30
lines changed

machine-learning/face-age-prediction/predict_age.py

+65-30
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ def get_faces(frame, confidence_threshold=0.5):
4545
for i in range(output.shape[0]):
4646
confidence = output[i, 2]
4747
if confidence > confidence_threshold:
48-
box = output[i, 3:7] * np.array([frame_width, frame_height, frame_width, frame_height])
48+
box = output[i, 3:7] * np.array([frame.shape[1], frame.shape[0], frame.shape[1], frame.shape[0]])
4949
# convert to integers
5050
start_x, start_y, end_x, end_y = box.astype(np.int)
5151
# widen the box a little
@@ -70,43 +70,78 @@ def display_img(title, img):
7070
cv2.destroyAllWindows()
7171

7272

73+
def get_optimal_font_scale(text, width):
74+
"""Determine the optimal font scale based on the hosting frame width"""
75+
for scale in reversed(range(0, 60, 1)):
76+
textSize = cv2.getTextSize(text, fontFace=cv2.FONT_HERSHEY_DUPLEX, fontScale=scale/10, thickness=1)
77+
new_width = textSize[0][0]
78+
if (new_width <= width):
79+
return scale/10
80+
return 1
81+
82+
# from: https://stackoverflow.com/questions/44650888/resize-an-image-without-distortion-opencv
83+
def image_resize(image, width = None, height = None, inter = cv2.INTER_AREA):
84+
# initialize the dimensions of the image to be resized and
85+
# grab the image size
86+
dim = None
87+
(h, w) = image.shape[:2]
88+
# if both the width and height are None, then return the
89+
# original image
90+
if width is None and height is None:
91+
return image
92+
# check to see if the width is None
93+
if width is None:
94+
# calculate the ratio of the height and construct the
95+
# dimensions
96+
r = height / float(h)
97+
dim = (int(w * r), height)
98+
# otherwise, the height is None
99+
else:
100+
# calculate the ratio of the width and construct the
101+
# dimensions
102+
r = width / float(w)
103+
dim = (width, int(h * r))
104+
# resize the image
105+
return cv2.resize(image, dim, interpolation = inter)
106+
107+
73108
def predict_age(input_path: str):
74109
"""Predict the age of the faces showing in the image"""
75110
# Read Input Image
76111
img = cv2.imread(input_path)
77-
# resize the image
78-
img = cv2.resize(img, (frame_width, frame_height))
79112
# Take a copy of the initial image and resize it
80113
frame = img.copy()
114+
if frame.shape[1] > frame_width:
115+
frame = image_resize(frame, width=frame_width)
81116
faces = get_faces(frame)
82117
for i, (start_x, start_y, end_x, end_y) in enumerate(faces):
83-
face_img = frame[start_y: end_y, start_x: end_x]
84-
# image --> Input image to preprocess before passing it through our dnn for classification.
85-
blob = cv2.dnn.blobFromImage(
86-
image=face_img, scalefactor=1.0, size=(227, 227),
87-
mean=MODEL_MEAN_VALUES, swapRB=False
88-
)
89-
# Predict Age
90-
age_net.setInput(blob)
91-
age_preds = age_net.forward()
92-
print("="*30, f"Face {i+1} Prediction Probabilities", "="*30)
93-
for i in range(age_preds[0].shape[0]):
94-
print(f"{AGE_INTERVALS[i]}: {age_preds[0, i]*100:.2f}%")
95-
i = age_preds[0].argmax()
96-
age = AGE_INTERVALS[i]
97-
age_confidence_score = age_preds[0][i]
98-
# Draw the box
99-
label = f"Age:{age} - {age_confidence_score*100:.2f}%"
100-
print(label)
101-
# get the position where to put the text
102-
yPos = start_y - 15
103-
while yPos < 15:
104-
yPos += 15
105-
# write the text into the frame
106-
cv2.putText(frame, label, (start_x, yPos),
107-
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), thickness=2)
108-
# draw the rectangle around the face
109-
cv2.rectangle(frame, (start_x, start_y), (end_x, end_y), color=(255, 0, 0), thickness=2)
118+
face_img = frame[start_y: end_y, start_x: end_x]
119+
# image --> Input image to preprocess before passing it through our dnn for classification.
120+
blob = cv2.dnn.blobFromImage(
121+
image=face_img, scalefactor=1.0, size=(227, 227),
122+
mean=MODEL_MEAN_VALUES, swapRB=False
123+
)
124+
# Predict Age
125+
age_net.setInput(blob)
126+
age_preds = age_net.forward()
127+
print("="*30, f"Face {i+1} Prediction Probabilities", "="*30)
128+
for i in range(age_preds[0].shape[0]):
129+
print(f"{AGE_INTERVALS[i]}: {age_preds[0, i]*100:.2f}%")
130+
i = age_preds[0].argmax()
131+
age = AGE_INTERVALS[i]
132+
age_confidence_score = age_preds[0][i]
133+
# Draw the box
134+
label = f"Age:{age} - {age_confidence_score*100:.2f}%"
135+
print(label)
136+
# get the position where to put the text
137+
yPos = start_y - 15
138+
while yPos < 15:
139+
yPos += 15
140+
# write the text into the frame
141+
cv2.putText(frame, label, (start_x, yPos),
142+
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), thickness=2)
143+
# draw the rectangle around the face
144+
cv2.rectangle(frame, (start_x, start_y), (end_x, end_y), color=(255, 0, 0), thickness=2)
110145
# Display processed image
111146
display_img('Age Estimator', frame)
112147
# save the image if you want
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
# Import Libraries
2+
import cv2
3+
import os
4+
import filetype
5+
import numpy as np
6+
7+
# The model architecture
8+
# download from: https://drive.google.com/open?id=1kiusFljZc9QfcIYdU2s7xrtWHTraHwmW
9+
AGE_MODEL = 'weights/deploy_age.prototxt'
10+
# The model pre-trained weights
11+
# download from: https://drive.google.com/open?id=1kWv0AjxGSN0g31OeJa02eBGM0R_jcjIl
12+
AGE_PROTO = 'weights/age_net.caffemodel'
13+
# Each Caffe Model impose the shape of the input image also image preprocessing is required like mean
14+
# substraction to eliminate the effect of illunination changes
15+
MODEL_MEAN_VALUES = (78.4263377603, 87.7689143744, 114.895847746)
16+
# Represent the 8 age classes of this CNN probability layer
17+
AGE_INTERVALS = ['(0, 2)', '(4, 6)', '(8, 12)', '(15, 20)',
18+
'(25, 32)', '(38, 43)', '(48, 53)', '(60, 100)']
19+
# download from: https://raw.githubusercontent.com/opencv/opencv/master/samples/dnn/face_detector/deploy.prototxt
20+
FACE_PROTO = "weights/deploy.prototxt.txt"
21+
# download from: https://raw.githubusercontent.com/opencv/opencv_3rdparty/dnn_samples_face_detector_20180205_fp16/res10_300x300_ssd_iter_140000_fp16.caffemodel
22+
FACE_MODEL = "weights/res10_300x300_ssd_iter_140000_fp16.caffemodel"
23+
24+
# Initialize frame size
25+
frame_width = 1280
26+
frame_height = 720
27+
28+
# load face Caffe model
29+
face_net = cv2.dnn.readNetFromCaffe(FACE_PROTO, FACE_MODEL)
30+
# Load age prediction model
31+
age_net = cv2.dnn.readNetFromCaffe(AGE_MODEL, AGE_PROTO)
32+
33+
34+
def get_faces(frame, confidence_threshold=0.5):
35+
"""Returns the box coordinates of all detected faces"""
36+
# convert the frame into a blob to be ready for NN input
37+
blob = cv2.dnn.blobFromImage(frame, 1.0, (300, 300), (104, 177.0, 123.0))
38+
# set the image as input to the NN
39+
face_net.setInput(blob)
40+
# perform inference and get predictions
41+
output = np.squeeze(face_net.forward())
42+
# initialize the result list
43+
faces = []
44+
# Loop over the faces detected
45+
for i in range(output.shape[0]):
46+
confidence = output[i, 2]
47+
if confidence > confidence_threshold:
48+
box = output[i, 3:7] * np.array([frame.shape[1], frame.shape[0], frame.shape[1], frame.shape[0]])
49+
# convert to integers
50+
start_x, start_y, end_x, end_y = box.astype(np.int)
51+
# widen the box a little
52+
start_x, start_y, end_x, end_y = start_x - \
53+
10, start_y - 10, end_x + 10, end_y + 10
54+
start_x = 0 if start_x < 0 else start_x
55+
start_y = 0 if start_y < 0 else start_y
56+
end_x = 0 if end_x < 0 else end_x
57+
end_y = 0 if end_y < 0 else end_y
58+
# append to our list
59+
faces.append((start_x, start_y, end_x, end_y))
60+
return faces
61+
62+
63+
def get_optimal_font_scale(text, width):
64+
"""Determine the optimal font scale based on the hosting frame width"""
65+
for scale in reversed(range(0, 60, 1)):
66+
textSize = cv2.getTextSize(text, fontFace=cv2.FONT_HERSHEY_DUPLEX, fontScale=scale/10, thickness=1)
67+
new_width = textSize[0][0]
68+
if (new_width <= width):
69+
return scale/10
70+
return 1
71+
72+
# from: https://stackoverflow.com/questions/44650888/resize-an-image-without-distortion-opencv
73+
def image_resize(image, width = None, height = None, inter = cv2.INTER_AREA):
74+
# initialize the dimensions of the image to be resized and
75+
# grab the image size
76+
dim = None
77+
(h, w) = image.shape[:2]
78+
# if both the width and height are None, then return the
79+
# original image
80+
if width is None and height is None:
81+
return image
82+
# check to see if the width is None
83+
if width is None:
84+
# calculate the ratio of the height and construct the
85+
# dimensions
86+
r = height / float(h)
87+
dim = (int(w * r), height)
88+
# otherwise, the height is None
89+
else:
90+
# calculate the ratio of the width and construct the
91+
# dimensions
92+
r = width / float(w)
93+
dim = (width, int(h * r))
94+
# resize the image
95+
return cv2.resize(image, dim, interpolation = inter)
96+
97+
98+
def predict_age():
99+
"""Predict the age of the faces showing in the image"""
100+
101+
# create a new cam object
102+
cap = cv2.VideoCapture(0)
103+
104+
while True:
105+
_, img = cap.read()
106+
# Take a copy of the initial image and resize it
107+
frame = img.copy()
108+
if frame.shape[1] > frame_width:
109+
frame = image_resize(frame, width=frame_width)
110+
faces = get_faces(frame)
111+
for i, (start_x, start_y, end_x, end_y) in enumerate(faces):
112+
face_img = frame[start_y: end_y, start_x: end_x]
113+
# image --> Input image to preprocess before passing it through our dnn for classification.
114+
blob = cv2.dnn.blobFromImage(
115+
image=face_img, scalefactor=1.0, size=(227, 227),
116+
mean=MODEL_MEAN_VALUES, swapRB=False
117+
)
118+
# Predict Age
119+
age_net.setInput(blob)
120+
age_preds = age_net.forward()
121+
print("="*30, f"Face {i+1} Prediction Probabilities", "="*30)
122+
for i in range(age_preds[0].shape[0]):
123+
print(f"{AGE_INTERVALS[i]}: {age_preds[0, i]*100:.2f}%")
124+
i = age_preds[0].argmax()
125+
age = AGE_INTERVALS[i]
126+
age_confidence_score = age_preds[0][i]
127+
# Draw the box
128+
label = f"Age:{age} - {age_confidence_score*100:.2f}%"
129+
print(label)
130+
# get the position where to put the text
131+
yPos = start_y - 15
132+
while yPos < 15:
133+
yPos += 15
134+
# write the text into the frame
135+
cv2.putText(frame, label, (start_x, yPos),
136+
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), thickness=2)
137+
# draw the rectangle around the face
138+
cv2.rectangle(frame, (start_x, start_y), (end_x, end_y), color=(255, 0, 0), thickness=2)
139+
# Display processed image
140+
cv2.imshow('Age Estimator', frame)
141+
if cv2.waitKey(1) == ord("q"):
142+
break
143+
# save the image if you want
144+
# cv2.imwrite("predicted_age.jpg", frame)
145+
cv2.destroyAllWindows()
146+
147+
148+
if __name__ == '__main__':
149+
predict_age()

0 commit comments

Comments
 (0)