概述
前面我写了很多篇关于OpenCV DNN应用相关的文章,这里再来一篇文章,用OpenCV DNN实现一个很有趣好玩的例子,基于Caffe的预训练模型实现年龄与性别预测,这个在很多展会上都有展示,OpenCV DNN实现这里非常简洁明了,总共不到100行的代码。下面就来说一下怎么实现的,首先下载两个Caffe的预训练模型:
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)'
人脸检测是基于OPenCV DNN模块自带的残差网络的人脸检测算法模型!非常的强大与好用!
实现步骤
完整的实现步骤需要如下几步:
-
预先加载三个网络模型
-
打开摄像头视频流/加载图像
-
对每一帧进行人脸检测
- 对检测到的人脸进行性别与年龄预测
- 解析预测结果
- 显示结果
代码实现详解
加载模型
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)
人脸检测
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)
性别与年龄预测
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 Output : {}".format(genderPreds))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))
运行效果(看到这个预测,我又相信技术了!@_@):
完整源代码:
import cv2 as cv
import timedef 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, bboxesfaceProto = "D:/projects/opencv_tutorial/data/models/face_detector/opencv_face_detector.pbtxt"
faceModel = "D:/projects/opencv_tutorial/data/models/face_detector/opencv_face_detector_uint8.pb"ageProto = "D:/projects/opencv_tutorial/data/models/cnn_age_gender_models/age_deploy.prototxt"
ageModel = "D:/projects/opencv_tutorial/data/models/cnn_age_gender_models/age_net.caffemodel"genderProto = "D:/projects/opencv_tutorial/data/models/cnn_age_gender_models/gender_deploy.prototxt"
genderModel = "D:/projects/opencv_tutorial/data/models/cnn_age_gender_models/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)# Open a video file or an image file or a camera stream
cap = cv.VideoCapture(0)
padding = 20
while cv.waitKey(1) < 0:# Read framet = time.time()hasFrame, frame = cap.read()frame = cv.flip(frame, 1)if not hasFrame:cv.waitKey()breakframeFace, bboxes = getFaceBox(faceNet, frame)if not bboxes:print("No face Detected, Checking next frame")continuefor 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 Output : {}".format(genderPreds))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))
任何程序错误,以及技术疑问或需要解答的,请添加
源码与模型下载地址
GitHub - xiaobingchan/opencv_tutorial: 基于OpenCV4.0 C++/Python SDK的案例代码演示程序与效果图像