| 【导读】本文是专栏《计算机视觉40例简介》的第40个案例《识别性别与年龄》。该专栏简要介绍李立宗主编《计算机视觉40例——从入门到深度学习(OpenCV-Python)》一书的40个案例。 目前,该书已经在电子工业出版社出版,大家可以在京东、淘宝、当当等平台购买。 大家可以在公众号“计算机视觉之光”回复关键字【案例40】获取本文案例的源代码及使用的测试图片等资料。 针对本书40个案例的每一个案例,分别录制了介绍视频。如果嫌看文字版麻烦,可以关注公众号“计算机视觉之光”直接观看视频介绍版。 本文简要介绍了本案例的一些基础知识,更详细的理论介绍、代码实现等内容请参考《计算机视觉40例简介》第28章《人脸识别应用案例》以获取更详细信息。 |
识别年龄和性别是一个有趣的应用,在很多场合我们都可以看到该应用。本文中,我们使用OpenCV自带的人脸检测器及Levi等人设计的卷积神经网络模型识别人脸对应的年龄和性别。
Levi等人在《Age and Gender Classification Using Convolutional Neural Networks》中提出了一种训练数据有限时也具有较好性能的卷积神经网络。其提出的网络模型如图1所示,它包含三个卷积层和两个全连接层。第一个卷积层包含 96 个7×7像素的卷积核,第二个卷积层包含 256 个 5×5 像素的卷积核,第三个卷积层包含 384 个3×3像素的卷积核。卷积层后面的两个全连接层,每个层包含 512 个神经元。最后的输出是每个分类所对应的标签。

图1 网络结构
其具体结构如图2所示,在第一个卷积层和第二个卷积层的后面都有ReLU层、最大池化层、局部响应归一化层 (Local Response Normalization,LRN) 。在第三个卷积层的后面仅有ReLU层、最大池化层。全连接层都具有512个神经元,第一个全连接层接收第三个卷积层的输入,第二个全连接层接收第一个全连接层的512个输出作为输入,两个全连接层后面都伴有ReLU层、随机失活(dropout)层。最后的输出是所有年龄、性别所对应的分类标签。

图2 具体结构
Levi等针对该论文在github上提供了官方网页,可以下载相应的实现代码和训练好的模型,本节使用的模型即来源于其官方网页。
识别年龄和性别核心代码:
- # ========自定义函数,获取人脸包围框===============
-
- def getBoxes(net, frame):
-
- frameHeight, frameWidth = frame.shape[:2] # 获取高度、宽度
-
- # 将图像(帧)处理为DNN可以接收的格式
-
- blob = cv2.dnn.blobFromImage(frame, 1.0, (300, 300),
-
- [104, 117, 123], True, False)
-
- # 调用网络模型,检测人脸
-
- net.setInput(blob)
-
- detections = net.forward()
-
- # faceBoxes存储检测到的人脸
-
- faceBoxes = []
-
- for i in range(detections.shape[2]):
-
- confidence = detections[0, 0, i, 2]
-
- if confidence > 0.7: #筛选一下,将置信度大于0.7侧保留,其余不要了
-
- 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)
-
- faceBoxes.append([x1, y1, x2, y2]) # 人脸框的坐标
-
- # 绘制人脸框
-
- cv2.rectangle(frame, (x1, y1), (x2, y2),
-
- (0, 255, 0), int(round(frameHeight / 150)),6)
-
- # 返回绘制了人脸框的帧frame、人脸包围框faceBoxes
-
- return frame, faceBoxes
-
- # ==========循环读取每一帧,并处理=========
-
- cap = cv2.VideoCapture(0, cv2.CAP_DSHOW) #装载摄像头
-
- while True:
-
- # 读一帧
-
- _, frame = cap.read()
-
- # 做个镜像处理,左右互换(避免和照镜子一样是反的)
-
- # frame = cv2.flip(frame, 1)
-
- # 调用函数getFaceBox,获取人脸包围框、绘制人脸包围框(可能多个)
-
- frame, faceBoxes = getBoxes(faceNet, frame)
-
- if not faceBoxes: #没有人脸时检测下一帧,后续循环操作不再继续。
-
- print("当前帧内不存在人脸")
-
- continue
-
- # 遍历每一个人脸包围框
-
- for faceBox in faceBoxes:
-
- # 处理frame,将其处理为符合DNN输入的格式
-
- blob = cv2.dnn.blobFromImage(frame, 1.0, (227, 227),mean)
-
- # 调用模型,预测性别
-
- genderNet.setInput(blob)
-
- genderOuts = genderNet.forward()
-
- gender = genderList[genderOuts[0].argmax()]
-
- # 调用模型,预测年龄
-
- ageNet.setInput(blob)
-
- ageOuts = ageNet.forward()
-
- age = ageList[ageOuts[0].argmax()]
-
- # 格式化文本(年龄、性别)
-
- result = "{},{}".format(gender, age)
-
- # 输出性别和年龄
-
- cv2.putText(frame, result, (faceBox[0], faceBox[1] - 10),
-
- cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 255), 2,
-
- cv2.LINE_AA)
-
- # 显示性别、年龄
-
- cv2.imshow("result", frame)
-
- # 按下Esc键,退出程序
-
- if cv2.waitKey(1) == 27:
-
- break
运行程序,程序运行结果如图3所示。

图3 运算结果
在《计算机视觉40例——从入门到深度学习(OpenCV-Python)》第28章《人脸识别应用案例》中详细介绍了人脸表情识别、驾驶员疲劳监测、易容术、识别性别与年龄等案例。
《计算机视觉40例——从入门到深度学习(OpenCV-Python)》在介绍Python基础、OpenCV基础、计算机视觉理论基础、深度学习理论的基础上,介绍了计算机视觉领域内具有代表性的40个典型案例。这些案例中,既有传统的案例(数字识别、答题卡识别、物体计数、缺陷检测、手势识别、隐身术、以图搜图、车牌识别、图像加密、指纹识别等),也有深度学习案例(图像分类、风格迁移、姿势识别、实例分割等),还有人脸识别方面的案例(表情识别、驾驶员疲劳监测、识别性别与年龄等)。
