opencv-137-DNN 实现性别与年龄预测

知识点

在OpenCV DNN中如何调用多个模型,相互配合使用
Gender Net and Age Net
https://www.dropbox.com/s/iyv483wz7ztr9gh/gender_net.caffemodel?dl=0”
https://www.dropbox.com/s/xfb20y596869vbb/age_net.caffemodel?dl=0”
上述两个模型一个是预测性别的,一个是预测年龄的。

性别预测返回的是一个二分类结果
Male
Female

年龄预测返回的是8个年龄的阶段!
‘(0-2)’,
‘(4-6)’,
‘(8-12)’,
‘(15-20)’,
‘(25-32)’,
‘(38-43)’,
‘(48-53)’,
‘(60-100)’

实现步骤:

  1. 完整的实现步骤需要如下几步:

  2. 预先加载三个网络模型

  3. 打开摄像头视频流/加载图像

  4. 对每一帧进行人脸检测

    • 对检测到的人脸进行性别与年龄预测
    • 解析预测结果
    • 显示结果

代码(c++,python)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#include <opencv2/opencv.hpp>
#include <opencv2/dnn.hpp>
#include <iostream>

using namespace cv;
using namespace cv::dnn;
using namespace std;

const size_t width = 300;
const size_t height = 300;
String model_bin = "D:/projects/opencv_tutorial/data/models/face_detector/opencv_face_detector_uint8.pb";
String config_text = "D:/projects/opencv_tutorial/data/models/face_detector/opencv_face_detector.pbtxt";

String ageProto = "D:/projects/opencv_tutorial/data/models/cnn_age_gender_models/age_deploy.prototxt";
String ageModel = "D:/projects/opencv_tutorial/data/models/cnn_age_gender_models/age_net.caffemodel";

String genderProto = "D:/projects/opencv_tutorial/data/models/cnn_age_gender_models/gender_deploy.prototxt";
String genderModel = "D:/projects/opencv_tutorial/data/models/cnn_age_gender_models/gender_net.caffemodel";
String ageList[] = { "(0-2)", "(4-6)", "(8-12)", "(15-20)", "(25-32)", "(38-43)", "(48-53)", "(60-100)" };
String genderList[] = { "Male", "Female" };
int main(int argc, char** argv) {
Mat frame = imread("D:/images/dannis2.jpg");
if (frame.empty()) {
printf("could not load image...\n");
return -1;
}
namedWindow("input image", WINDOW_AUTOSIZE);
imshow("input image", frame);

Net net = readNetFromTensorflow(model_bin, config_text);
net.setPreferableBackend(DNN_BACKEND_OPENCV);
net.setPreferableTarget(DNN_TARGET_CPU);

Net ageNet = readNet(ageModel, ageProto);
Net genderNet = readNet(genderModel, genderProto);

Mat blobImage = blobFromImage(frame, 1.0,
Size(300, 300),
Scalar(104.0, 177.0, 123.0), false, false);

net.setInput(blobImage, "data");
Mat detection = net.forward("detection_out");
vector<double> layersTimings;
double freq = getTickFrequency() / 1000;
double time = net.getPerfProfile(layersTimings) / freq;
printf("execute time : %.2f ms\n", time);
int padding = 20;
Mat detectionMat(detection.size[2], detection.size[3], CV_32F, detection.ptr<float>());
float confidence_threshold = 0.5;
for (int i = 0; i < detectionMat.rows; i++) {
float confidence = detectionMat.at<float>(i, 2);
if (confidence > confidence_threshold) {
size_t objIndex = (size_t)(detectionMat.at<float>(i, 1));
float tl_x = detectionMat.at<float>(i, 3) * frame.cols;
float tl_y = detectionMat.at<float>(i, 4) * frame.rows;
float br_x = detectionMat.at<float>(i, 5) * frame.cols;
float br_y = detectionMat.at<float>(i, 6) * frame.rows;

Rect object_box((int)tl_x, (int)tl_y, (int)(br_x - tl_x), (int)(br_y - tl_y));

Rect roi;
roi.x = max(0, object_box .x - padding);
roi.y = max(0, object_box.y - padding);
roi.width = min(object_box .width+ padding, frame.cols - 1);
roi.height = min(object_box.height + padding, frame.rows - 1);
Mat face = frame(roi);
Mat faceblob = blobFromImage(face, 1.0, Size(227, 227), Scalar(78.4263377603, 87.7689143744, 114.895847746), false, false);
ageNet.setInput(faceblob);
genderNet.setInput(faceblob);
Mat agePreds = ageNet.forward();
Mat genderPreds = genderNet.forward();

Mat probMat = agePreds.reshape(1, 1);
Point classNumber;
double classProb;
minMaxLoc(probMat, NULL, &classProb, NULL, &classNumber);
int classidx = classNumber.x;
String age = ageList[classidx];

probMat = genderPreds.reshape(1, 1);
minMaxLoc(probMat, NULL, &classProb, NULL, &classNumber);
classidx = classNumber.x;
String gender = genderList[classidx];
rectangle(frame, object_box, Scalar(0, 0, 255), 2, 8, 0);
putText(frame, format("age:%s gender:%s", age.c_str(), gender.c_str()), object_box.tl(), FONT_HERSHEY_SIMPLEX, 0.8, Scalar(255, 0, 0), 1, 8);
}
}
imshow("ssd-face-detection", frame);

waitKey(0);
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
"""
DNN 实现性别与年龄预测
"""

import cv2 as cv
import time


def getFaceBox(net, frame, conf_threshold=0.7):
frameOpencvDnn = frame.copy()
frameHeight = frameOpencvDnn.shape[0]
frameWidth = frameOpencvDnn.shape[1]
blob = cv.dnn.blobFromImage(frameOpencvDnn, 1.0, (300, 300), [104, 117, 123], True, False)

net.setInput(blob)
detections = net.forward()
bboxes = []
for i in range(detections.shape[2]):
confidence = detections[0, 0, i, 2]
if confidence > conf_threshold:
x1 = int(detections[0, 0, i, 3] * frameWidth)
y1 = int(detections[0, 0, i, 4] * frameHeight)
x2 = int(detections[0, 0, i, 5] * frameWidth)
y2 = int(detections[0, 0, i, 6] * frameHeight)
bboxes.append([x1, y1, x2, y2])
cv.rectangle(frameOpencvDnn, (x1, y1), (x2, y2), (0, 255, 0), int(round(frameHeight / 150)), 8)
return frameOpencvDnn, bboxes


faceProto = "opencv_face_detector.pbtxt"
faceModel = "opencv_face_detector_uint8.pb"

ageProto = "age_deploy.prototxt"
ageModel = "age_net.caffemodel"

genderProto = "gender_deploy.prototxt"
genderModel = "gender_net.caffemodel"

MODEL_MEAN_VALUES = (78.4263377603, 87.7689143744, 114.895847746)
ageList = ['(0-2)', '(4-6)', '(8-12)', '(15-20)', '(25-32)', '(38-43)', '(48-53)', '(60-100)']
genderList = ['Male', 'Female']

# Load network
ageNet = cv.dnn.readNet(ageModel, ageProto)
genderNet = cv.dnn.readNet(genderModel, genderProto)
faceNet = cv.dnn.readNet(faceModel, faceProto)

cap = cv.VideoCapture(0)
padding = 20
while cv.waitKey(1) < 0:
t = time.time()
hasFrame, frame = cap.read()
frame = cv.flip(frame, 1)
if not hasFrame:
cv.waitKey()
break

frameFace, bboxes = getFaceBox(faceNet, frame)
if not bboxes:
print("No face Detected, Checking next frame")
continue

for bbox in bboxes:
# print(bbox)
face = frame[max(0, bbox[1] - padding):min(bbox[3] + padding, frame.shape[0] - 1),
max(0, bbox[0] - padding):min(bbox[2] + padding, frame.shape[1] - 1)]

blob = cv.dnn.blobFromImage(face, 1.0, (227, 227), MODEL_MEAN_VALUES, swapRB=False)
genderNet.setInput(blob)
genderPreds = genderNet.forward()
gender = genderList[genderPreds[0].argmax()]
print("Gender : {}, conf = {:.3f}".format(gender, genderPreds[0].max()))

ageNet.setInput(blob)
agePreds = ageNet.forward()
age = ageList[agePreds[0].argmax()]
print("Age Output : {}".format(agePreds))
print("Age : {}, conf = {:.3f}".format(age, agePreds[0].max()))

label = "{},{}".format(gender, age)
cv.putText(frameFace, label, (bbox[0], bbox[1] - 10), cv.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 255), 2,
cv.LINE_AA)
cv.imshow("Age Gender Demo", frameFace)
print("time : {:.3f} ms".format(time.time() - t))

cv.waitKey(0)
cv.destroyAllWindows()

结果

代码地址

github