基于深度学习的人脸性别识别系统(含UI界面,Python代码)
阅读原文时间:2022年04月19日阅读:2

摘要:人脸性别识别是人脸识别领域的一个热门方向,本文详细介绍基于深度学习的人脸性别识别系统,在介绍算法原理的同时,给出P__y__t__h__o__n的实现代码以及P__y__Q__t的UI界面。在界面中可以选择人脸图片、视频进行检测识别,也可通过电脑连接的摄像头设备进行实时识别人脸性别;可对图像中存在的多张人脸进行性别识别,可选择任意一张人脸框选显示结果,检测速度快、识别精度高。博文提供了完整的Python代码和使用教程,适合新入门的朋友参考,完整代码资源文件请转至文末的下载链接。本博文目录如下:

目录

➷点击跳转至文末所有涉及的完整代码文件下载页☇

完整资源下载链接https://mianbaoduo.com/o/bread/YpmXk5xv

代码介绍及演示视频链接:https://www.bilibili.com/video/BV15Y4y1v7AB/(正在更新中,欢迎关注博主B站视频)


前言

随着科技的发展,人脸识别以及性别检测在日常生活中的应用越来越广泛,由于人脸图像的生物特征识别是非接触的,比较简单快速,还具有一定的娱乐性,在社交网络、视频监控、人机交互等领域具有广阔的应用前景。本文使用OpenCV算法,实现人脸检测以及性别识别,用户可以选择传入图片、视频、或者摄像头实时摄影作为检测的文件。

人脸性别识别,其实是人脸属性识别的一种,即根据图像中的人脸判断其性别属于男性还是女性,该任务本身具有较强的现实意义。前面博主分享有人脸表情识别系统介绍的博文,可以认为是检测人脸的表情属性[1],对性别的识别算是继续人脸识别的小专题。这里博主分享一个性别识别的小项目,供大家参考学习了。

网上的人脸性别识别程序代码很多,大部分都是采用OpenCV算法和face_recognition等识别单张图片中的人脸,虽然后者的算法相较于前者更简单,但是对于大多数Windows用户想要下载这个库是很困难的,所以本博文使用对Windows用户更友好的OpenCV算法来完成。网上的人脸性别识别程序脚本很多,但几乎没有人将其开发成一个可以展示的完整软件,并不方便选择文件和实时检测。对此这里给出博主设计的界面,同款的简约风,功能也可以满足图片、视频和摄像头的识别检测,希望大家可以喜欢,初始界面如下图:

检测人脸时的界面截图(点击图片可放大)如下图,可识别画面中存在的多个人脸,也可开启摄像头或视频检测:

详细的功能演示效果参见博主的B站视频或下一节的动图演示,觉得不错的朋友敬请点赞、关注加收藏!系统UI界面的设计工作量较大,界面美化更需仔细雕琢,大家有任何建议或意见和可在下方评论交流。


1. 效果演示

软件好不好用,颜值很重要,首先我们还是通过动图看一下识别性别的效果,系统主要实现的功能是对图片、视频和摄像头画面中的人脸性别属性进行识别,识别的结果可视化显示在界面和图像中,另外提供多个人脸的显示选择功能,演示效果如下。

(一)选择人脸图片识别

系统允许选择图片文件进行识别,点击图片选择按钮图标选择图片后,显示所有人脸识别的结果,可通过下拉选框查看单个人脸的结果。本功能的界面展示如下图所示:

(二)人脸视频识别效果展示

很多时候我们需要识别一段视频中的人脸属性,这里设计了视频选择功能。点击视频按钮可选择待检测的视频,系统会自动解析视频逐帧识别人脸,并将结果记录在右下角表格中,效果如下图所示:

(三)摄像头检测效果展示

在真实场景中,我们往往利用设备摄像头获取实时画面,同时需要对画面中的人脸性别进行识别,因此本文考虑到此项功能。如下图所示,点击摄像头按钮后系统进入准备状态,系统显示实时画面并开始检测画面中的人脸,识别结果展示如下图:


2. 人脸检测与性别识别

人脸性别识别可看成是通过人脸图像信息自动发掘和分析人脸属性的二分类问题。在广告定向投放、个性化智能推荐、人脸属性分析等方面得到广泛应用。如今人工智能横扫经典算法,因此以卷积神经网络为代表的深度学习方法自然就被广泛用于人脸性别识别研究。本文借助OpenCV算法,实现人脸检测以及性别识别,这里首先对实现原理进行介绍。

本文所使用的模型是由 Gil Levi 和Tal Hassner 发布在CVPR的《Age and Gender Classification using Convolutional Neural Networks》论文,论文旨在缩小自动人脸识别能力与年龄性别估计方法之间的差距[2]。论文使用Adience数据集,该数据集包含比LFW数据集的图像更具挑战性,使用一个健壮性更强的系统提升性能,以更好地利用来自大量示例训练集的信息。

这里使用的是一种以上论文提出的卷积神经网络架构,类似于 CaffeNet 和 AlexNet。该网络使用 3 个卷积层、2 个全连接层和一个最终输出层。首先原始图像被缩放至\(256 \times 256\)的尺寸,对图像进行中心裁剪,得到尺寸为\(227 \times 227\)的图像作为网络输入,该网络结构如下图所示:

  1. 尺寸为\(96 \times 3 \times 7 \times 7\)的卷积核,接ReLU层、MaxPooling(\(3 \times 3, stride=2\))、归一化层,输出尺寸:\(96 \times 28 \times 28\);
  2. 尺寸为\(96 \times 5 \times 5 \times 256\)的卷积核,接ReLU层、MaxPooling(\(3 \times 3, stride=2\))、归一化层,输出尺寸:\(256 \times 14 \times 14\);
  3. 尺寸为\(256 \times 14 \times 14 \times 384\)的卷积核,接ReLU层、MaxPooling(\(3 \times 3\))$;
  4. 全连接层(512个神经元),接ReLU层及Dropout层;
  5. 全连接层(512个神经元),接ReLU层及Dropout层;
  6. 根据性别映射到最后的类别输出。

利用以上网络进行训练,所有层中的权重均采用标准偏差为0.01,均值为0的高斯随机值初始化。训练时不使用预训练模型,不使用基准可用的图像和标签之外的任何数据,网络从头开始进行训练。训练的目标值用与真实类别相对应的稀疏二进制向量表示,对于每个训练图像,目标标签向量具有类数的长度,在真实值所在索引位置为1,在其他位置为0。训练基于Adience数据集,使用随机梯度下降算法进行训练,其中批量大小(Batch Size)设置为50,初始学习率为\(e-3\),在\(10K\)次迭代后降为\(e-4\)。

这里我们利用OpenCV导入该算法,调用电脑自带的摄像头获取画面,并对画面中的人脸进行性别识别。首先需要导入用到的Python库:

import cv2 as cv
import time
import argparse

然后导入我们下载到的训练模型,主要有人脸检测和性别识别的模型,代码如下:

faceProto = "opencv_face_detector.pbtxt"
faceModel = "opencv_face_detector_uint8.pb" # 检测人脸的模型,

genderProto = "gender_deploy.prototxt"
genderModel = "gender_net.caffemodel" # 判断性别的模型
MODEL_MEAN_VALUES = (78.4263377603, 87.7689143744, 114.895847746)
genderList = ['Male', 'Female'] # 性别列表

# 加载 network
genderNet = cv.dnn.readNet(genderModel, genderProto)
faceNet = cv.dnn.readNet(faceModel, faceProto)

接下来我们定义获得图像/视频的人脸信息的函数,使用模型对图像中的人脸进行检测,框出人脸位置:

def getFace(frame):
    conf_threshold = 0.7
    # 获取图像的信息,以便之后对图像的操作
    height = frame.copy().shape[0]
    width = frame.copy().shape[1]
    # 对图片进行预处理, frame就是我们读取到视频的每一帧,最后输出的大小是300*300
    # 同时也帮助我们减均值抵抗亮度的变化对模型造成的不良影响
    # 为了消除同一场景下不同光照的图片,对我们最终的分类或者神经网络的影响,
    # 我们常常对图片的R、G、B通道的像素求一个平均值,然后将每个像素值减去我们的平均值,
    # 这样就可以得到像素之间的相对值,就可以排除光照的影响。
    frameblob = cv.dnn.blobFromImage(frame.copy(), 1.0, (300, 300), [104, 117, 123], True, False)
    # 识别人脸
    faceNet.setInput(frameblob)# 将预处理后的图像输入网络
    detections = faceNet.forward() # 将图像向前传播,检测可以检测到的东西
    box = []  # 用来保留检测到的结果
    # 遍历所有的结果, 并将可行的放到我们最终的结果中
    for i in range(detections.shape[2]):
        confidence = detections[0, 0, i, 2]  # 得到检测结果的分数
        if confidence > conf_threshold: # 大于阈值就是我们需要的结果
            # 取出相对坐标并获得原坐标
            x1 = int(detections[0, 0, i, 3] * width)
            y1 = int(detections[0, 0, i, 4] * height)
            x2 = int(detections[0, 0, i, 5] * width)
            y2 = int(detections[0, 0, i, 6] * height)
            box.append([x1, y1, x2, y2])
            # 绘图
            cv.rectangle(frame.copy(), (x1, y1), (x2, y2), (0, 255, 0), int(round(height / 150)), 8)
    return frame.copy(), box

以上函数传入的参数是图像的信息,经过该函数的处理,我们检测图像中包含的信息,然后通过上述论文模型的预测,取出图像中可能是人脸数据的值,这些就是最后用来预测的数据,该步骤主要用的就是facenet这个神经网络模型,使用该模型之后能够大大增加数据的准确性,让后面的预测模型更加精准。

FaceNet是谷歌于CVPR2015.02发表,提出了一个对识别(这是谁?)、验证(这是用一个人吗?)、聚类(在这些面孔中找到同一个人)等问题的统一解决框架,即它们都可以放到特征空间里统一处理,只需要专注于解决的仅仅是如何将人脸更好的映射到特征空间[3]。其本质是通过卷积神经网络学习人脸图像到128维欧几里得空间的映射,该映射将人脸图像映射为128维的特征向量,联想到二维空间的相关系数的定义,使用特征向量之间的距离的倒数来表征人脸图像之间的"相关系数"(为了方便理解,后文称之为相似度),对于相同个体的不同图片,其特征向量之间的距离较小(即相似度较大),对于不同个体的图像,其特征向量之间的距离较大(即相似度较小)。最后基于特征向量之间的相似度来解决人脸图像的识别、验证和聚类等问题。论文地址如下:https://arxiv.org/abs/1503.03832

如上图所示,FaceNet由一个批量输入层和一个深度卷积神经网络(CNN )组成,然后是 L2 归一化和之后的人脸嵌入,最后使用三元组损失函数进行训练。图像经过该模型后就可以得到图像中人脸的基本信息特征,接下来调用导入的辨别gender的模型就可以完成人脸的识别,调用和标记识别结果的代码如下:

def face_pred(cap):
    padding = 20
    while cv.waitKey(1) < 0:
        # 读取 frame
        t = time.time()
        # 读取视频中的帧
        hasFrame, frame = cap.read()
        if not hasFrame:
            # 等待键盘发出命令
            cv.waitKey(100)
            break
        frameFace, bboxes = getFace(frame)
        # if not bboxes:
        #     continue
        for bbox in bboxes:
            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()]
            label = "{}".format(gender)
            cv.putText(frameFace, label, (bbox[0], bbox[1] - 10), cv.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 255), 2,
                       cv.LINE_AA)
            cv.imshow("Gender_recognition", frameFace)

该函数传入的参数是视频的数据,读取视频的函数是cv.VideoCapture( ),如果该函数的参数是0,那么就会调用系统摄像头,获取本人的人脸数据,如果传入的参数是一个文件地址,那么就会预测传入视频的性别。最终运行以上函数进行识别的代码如下:

cap = cv.VideoCapture(0)
face_pred(cap)

运行以上演示脚本,达到的结果如下图所示,性别识别结果被显示在人脸上方。有了以上的思路,我们可以在此基础上利用PyQt5设计UI界面,将图片、视频选择和摄像头功能更好展示在界面中。

打开QtDesigner软件,拖动以下控件至主窗口中,调整界面样式和控件放置,性别识别系统的界面设计如下图所示:

控件界面部分设计好,接下来利用PyUIC工具将.ui文件转化为.py代码文件,通过调用界面部分的代码同时加入对应的逻辑处理代码。博主对其中的UI功能进行了详细测试,最终开发出一版流畅得到清新界面,就是博文演示部分的展示,完整的UI界面、测试图片视频、代码文件,以及Python离线依赖包(方便安装运行,也可自行配置环境),均已打包上传,感兴趣的朋友可以通过下载链接获取。


下载链接

若您想获得博文中涉及的实现完整全部程序文件(包括测试图片、视频,py, UI文件等,如下图),这里已打包上传至博主的面包多平台和CSDN下载资源。本资源已上传至面包多网站和CSDN下载资源频道,可以点击以下链接获取,已将所有涉及的文件同时打包到里面,点击即可运行,完整文件截图如下:

在文件夹下的资源显示如下,其中包含了Python的离线依赖包,读者可在正确安装Anaconda和Pycharm软件后,点击bat文件进行安装,详细演示也可见本人B站视频。

注意:本资源已经过调试通过,下载后可通过Pycharm运行;运行界面的主程序为runMain.py,测试摄像头或视频脚本可运行main.py,为确保程序顺利运行,请配置Python依赖包的版本如下:➷➷➷

Python版本:3.8,请勿使用其他版本,详见requirements.txt文件;

certifi == 2021.10.8
click == 7.1.2
numpy == 1.22.3
opencv-python == 4.5.5.64
Pillow == 9.0.1
PyQt5 == 5.15.4
pyqt5-plugins == 5.15.4.2.2
PyQt5-Qt5 == 5.15.2
PyQt5-sip == 12.9.1
pyqt5-tools == 5.15.4.3.2
python-dotenv == 0.19.2
qt5-applications == 5.15.2.2.2
qt5-tools == 5.15.2.1.2
wincertstore == 0.2

完整资源下载链接1https://mianbaoduo.com/o/bread/YpmXk5xv

完整资源下载链接2博主在CSDN下载频道的完整资源下载页


结束语

由于博主能力有限,博文中提及的方法即使经过试验,也难免会有疏漏之处。希望您能热心指出其中的错误,以便下次修改时能以一个更完美更严谨的样子,呈现在大家面前。同时如果有更好的实现方法也请您不吝赐教。