Predict Age and Gender according the deteced faces with CNN and opencv
用CNN、HAAR检测视频/图像/摄像头中的人脸,用caffemodel、keras、tensorflow根据检测到的人脸进行年龄和性别的预测,可以在命令行菜单中选择检测源和检测模型,后续可以简便的扩展更多检测模型,只需安装opencv,Python,keras就可以试玩,欢迎围观。
环境说明
本文介绍的工程运行环境,本文源代码以及相应文件已上传至Github.
1. Win10 X64
文中有提到不同方法处理图片的时间,该处理时间随CPU不同而不同,测试CPU: Intel Core i7-8550U CPU with 8G RAM, win10 x64
2. python3.6 OpenCV-python
3. keras/tensorflow
安装方法参考Install keras and tensorflow cpu on Windows
参考链接
这是一个优秀的项目,作者对现有的性别和年龄预测相关的开源项目进行了很多研究,并在该项目中做了很好的总结。
本文基于该开源项目,新增了命令行菜单,可以选择检测源,选择用于检测人脸的模型,以及选择预测年龄和性别的模型,便于不同模型间检测效果的对比;同时本文更改了main.py的结构,便于后续添加更多的检测模型。
2. 本文的测试视频和图像来自于这里:https://www.youtube.com/watch?v=cSSFRim8OK8。
3. Predict Age and Gender using Convolutional Neural Network and openCV 这篇文章中使用的人脸检测为是本文中的HAAR,年龄和性别预测为本文中提到的Caffenet。这篇文章最有趣的部分是其检测源:优酷视频的链接,通过使用python中的pafy和youtube_dl来获取检测源。但是youtube_dl通常由于youtube的措施而无法获取视频。有类似的需求的同学可以参考。
非常感谢原作者的分享!
使用步骤
1. choose detect source:videos/images/camera
videos:将要检测的视频(.mp4)放在“ videos /”文件夹中,然后选择“videos”作为检测源。
images:将要检测的图像放在文件夹images /中,然后选择“images”作为检测源。
camera:如果选择摄像头作为检测源,则程序将打开计算机的摄像头并检测其捕获的内容。
2.choose face detector: HAAR/Tensornet
HAAR:由opencv中的CascadeClassifier函数加载。
Tensornet:由opencv中的readNetFromTensorflow函数加载。
3.choose age and gender detector:ssrnet/Caffenet
ssrnet:此模型来自SSR-Net。它属于keras和tensorflow框架,该模型输出性别(数字,其中0=女性,1=男性)和年龄(数字)。
Caffenet:此模型来自AgeGenderDeepLearning,它以Caffe模型发布,可以由opencv中的readNetFromCaffe加载。它输出性别(两个二进制类别:男性和女性)和年龄(8个类别:[0..2],[4..6],[8..12],[15..20], [25..32],[38..43],[48..53],[60..100])。
Caffe模型具有2个相关文件:
prototxt,该文件定义了神经网络中的各层,各层的输入,输出和功能。
caffemodel,包含经过训练的神经网络(经过训练的模型)的信息。
4.RUN
确认以上选项后,选择此选项后,程序将开始处理视频或图像,按ESC键可中止程序运行。
若以默认值运行,则程序将以检测videos/Tensornet/ssrnet进行检测。
程序结构
1. 创建菜单,从菜单中选择检测源,检测模型并运行。
在main.py中调用菜单并返回相应变量。
1 2 |
from menu import menu source,face_detector, age_gender,bRuning = menu() |
各级菜单名称存放在List中,根据当前选项决定下一步显示的菜单以及相应动作。后续若要添加更多的检测模型,将模型名称添加到相应的List中即可。
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 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
mainList = ['choose detect source', 'choose face detector', 'choose age and gender detector','RUN', 'exit'] sourceList = ['images', 'videos', 'camera', 'back to main menu'] faceList = ['HAAR', 'Tensornet', 'back to main menu'] ageList = ['ssrnet', 'Caffenet', 'back to main menu'] def print_mainmenu(): print ("="*20 + "Main menu" + "="*20) for i in mainList: print (mainList.index(i) + 1, i) print(" ") def print_sourcemenu(): print ("="*20 + "Source menu" + "="*20) for i in sourceList: print (sourceList.index(i) + 1, i) print(" ") def print_facedetectoremenu(): print ("="*20 + "face detector menu" + "="*20) for i in faceList: print (faceList.index(i) + 1, i) print(" ") def print_agegendermenu(): print ("="*20 + "age gender detector menu" + "="*20) for i in ageList: print (ageList.index(i) + 1, i) print(" ") def menu(): #set default value for source/faceDetector/agDetector source = sourceList[1] faceDetector = faceList[1] agDetector = ageList[0] bRuning = False print_mainmenu() while True: #get user input try: num = int(input("Please choose the step:")) except IndexError: print("Please input a valid value:(1.2.3.4.5)") continue #process the function according the user input if num == 1: print_sourcemenu() while True: #get user input try: srcnum = int(input("Please choose the source:")) except IndexError: print("Please input a valid value:(1.2.3.4)") continue if srcnum == 1 or srcnum == 2 or srcnum == 3: source = sourceList[srcnum - 1] print("The detect source come from " + source) print(" ") print_mainmenu() break elif srcnum == 4: print_mainmenu() break else: print("input invalid!") elif num == 2: print_facedetectoremenu() while True: #get user input try: facenum = int(input("Please choose the face detector:")) except IndexError: print("Please input a valid value:(1.2.3)") continue if facenum == 1 or facenum == 2: faceDetector = faceList[facenum - 1] print("The face detector is " + faceDetector) print(" ") print_mainmenu() break elif facenum == 3: print_mainmenu() break else: print("input invalid!") elif num == 3: print_agegendermenu() while True: #get user input try: agenum = int(input("Please choose age gender detector:")) except IndexError: print("Please input a valid value:(1.2.3)") continue if agenum == 1 or agenum == 2: agDetector = ageList[agenum - 1] print("The age gender detector is " + agDetector) print(" ") print_mainmenu() break elif agenum == 3: print_mainmenu() break else: print("input invalid!") elif num == 4: print("The detect source come from " + source) print("The face detector is " + faceDetector) print("The age gender detector is " + agDetector) bRuning = True break elif num == 5: break else: print("input invalid!") return(source, faceDetector,agDetector,bRuning) |
2. 加载人脸检测模型,年龄/性别检测模型,在cmd.exe中输出模型加载时间
将人脸检测模型名称及其加载函数,年龄、性别检测模型及其加载函数放在各自的字典中,main函数中根据菜单选项来决定调用内容。后续扩展模型时,准备好模型文件与相应的加载函数,将模型名称与函数名称添加到字典中即可,不需要更改main()的代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
load_face_dict = { 'HAAR':load_face_HAAR, 'Tensornet':load_face_Tensornet } load_agender_dict = { 'ssrnet':load_agender_ssrnet, 'Caffenet':load_agender_Caffenet } #以下内容为main()函数中的部分代码 time_start = time.time() load_face_fun = load_face_dict.get(face_detector) face_net = load_face_fun() time_end = time.time() print ("load face detector Time:",time_end - time_start) time_start = time.time() load_agender_fun = load_agender_dict.get(age_gender) gender_net,age_net = load_agender_fun() time_end = time.time() print ("load agender detector Time:",time_end - time_start) |
3. 为提高人脸检测的处理速度,将原视频帧或原图按设定尺寸缩小,并从缩小的图像中进行人脸检测。处理小图像的速度更快,但并不影响质人脸检测的质量(该结论来自于diovisgood/agender,我并未验证,有兴趣的同学可以验证一下)。
默认设定缩小后的尺寸为640*480,函数calculateParameter会根据源图像的尺寸和该设定值重新计算缩小后的尺寸,完整的代码请参考Github。
与加载模型类似,将人脸检测模型名称和人脸检测函数的名称放在字典detect_face_dict中,图像处理函数根据菜单选项调用相应的函数,后续扩展其他模型时,只需要添加模型名和检测函数,不需要修改图像处理函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
width = 640 height = 480 detect_face_dict = { 'HAAR':detect_face_HAAR, 'Tensornet':detect_face_Tensornet } #以下代码为子函数process_image()中的部分代码 if (diagonal is None): calculateParameters(height_orig, width_orig) # Resize, Convert BGR to HSV if ((height, width) != frame.shape[0:2]): frame_bgr = cv.resize(frame, dsize=(width, height), fx=0, fy=0) else: frame_bgr = frame detect_face_fun = detect_face_dict.get(face_detector) # Detect faces face_boxes = detect_face_fun(frame_bgr,face_net) |
4. 性别和年龄检测需要更多的人脸细节,因此将人脸检测的结果还原到原视频帧或原图的坐标,并从原图中获取人脸部分, 根据获取的人脸预测性别和年龄;在每个人脸周围绘制一个矩形,并在标签上标注性别和年龄,在cmd.exe中打印当前图像的处理时间(人脸检测,年龄性别预测的总时间)。
如下代码所示,性别和年龄检测模型及其相应的函数名放在字典中,方便后续扩展。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
predictAgeGender_dict = { 'ssrnet':predictAgeGender_ssrnet, 'Caffenet':predictAgeGender_Caffenet } #以下为子函数process_image()中的部分代码 predictAgeGender_fun = predictAgeGender_dict.get(age_gender) if (len(face_boxes) > 0): # Draw boxes in faces_bgr image for (x1, y1, x2, y2) in face_boxes: cv.rectangle(faces_bgr, (x1, y1), (x2, y2), color=(0, 255, 0), thickness=line_thickness, lineType=8) # Collect all faces into matrix faces = collectFaces(frame, face_boxes,height_orig, width_orig) # Get age and gender labels = predictAgeGender_fun(faces,gender_net,age_net) # Draw labels for (label, box) in zip(labels, face_boxes): cv.putText(faces_bgr, label, org=(box[0], box[1] - 10), fontFace=cv.FONT_HERSHEY_PLAIN, fontScale=1, color=(0, 64, 255), thickness=1, lineType=cv.LINE_AA) cv.imshow('Faces', faces_bgr) |
模检测型扩展
如果要添加更多的人脸检测模型或年龄性别检测模型,可按以下步骤进行:
1.准备模型文件,并将其放入合适的文件夹中。
2.将模型名称添加到menu.py中的faceList或ageList中。
1 2 |
faceList = ['HAAR', 'Tensornet', 'back to main menu'] ageList = ['ssrnet', 'Caffenet', 'back to main menu'] |
3.准备新模型的加载和检测函数,注意相应函数的输入输出与现有模型相应函数的输入输出一致,将新增函数添加到main.py。
4.将新增的模型名称,以及加载和检测函数名,添加到main.py中的load_face_dict / detect_face_dict / load_agender_dict / predictAgeGender_dict词典中。词典中的模型名称应与步骤2中的名称一致。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
load_face_dict = { 'HAAR':load_face_HAAR, 'Tensornet':load_face_Tensornet } detect_face_dict = { 'HAAR':detect_face_HAAR, 'Tensornet':detect_face_Tensornet } load_agender_dict = { 'ssrnet':load_agender_ssrnet, 'Caffenet':load_agender_Caffenet } predictAgeGender_dict = { 'ssrnet':predictAgeGender_ssrnet, 'Caffenet':predictAgeGender_Caffenet } |
本文到此结束,感谢阅读,谢谢支持。