论文部分内容阅读
【摘 要】近几年深度学习大火,而人脸识别又是深度学习的典型代表。TensorFlow是深度学习的一个平台,主要通过搭建卷积神经网络系统来对图片样本进行特征识别、分类训练,进而达到人脸的识别。本系统调用了OpenCV计算机视觉库中的功能函数,通过USB摄像头实时截取人脸图像,然后进行Haar特征识别以及Adaboost分类器的分类训练,最后打开摄像头,将捕捉到的人脸与训练好的图片进行对比,从而达到人脸识别的效果。
【关键词】深度学习;人脸识别;卷积神经网络;OpenCV;TensorFlow
人脸识别本质是用一个几何特征矢量来表示人脸,并根据模式识别中层次聚类的思想设计分类器,达到识别目的。调用OpenCV库中的功能函数来截取视频中的图像帧数据,并进行一系列预处理,完成图片的灰度化以及统一图片的大小和格式,然后再将这些图片输入到搭建好的卷积神经网络中进行训练,训练完成后将生成一个训练模型,此模型便是人脸识别时的评估标准。
一、模块功能及结构划分
系统共分为四个部分,分别为:实时人脸截取模块、图片预处理模块、CNN搭建和训练模块以及人脸检测模块。
实时人脸截取模块主要负责采集人脸图片。管理员输入要采集的人员姓名,后台生成以该姓名为名称的文件夹,然后使用USB摄像头获取视频数据,利用OpenCV的功能函数定位人脸部分,截取一帧的图像数据保存到该文件夹下,当采集数量达到设定的数量后,摄像头关闭。
图片预处理模块主要负责图片灰度化、像素归一化、图片大小规格化以及为每一类图片夹指定一个唯一的标签,便于后面的训练。
CNN搭建和训练模块主要完成搭建神经网络、划分训练集和验证集、深度学习训练以及训练模型的保存,有了训练模型后就能进行人脸识别了。
人脸检测模块主要调用摄像头来获取人脸图片,读入之前训练成熟的网路模型来进行人脸识别。
二、项目原理
(一)人脸识别分类器
1.Haar特征
Haar特征分为三类:边缘特征、线性特征、中心特征和对角线特征,组合成特征模板。特征模板内有白色和黑色两种矩形,并定义该模板的特征值为白色矩形像素和减去黑色矩形像素和(在opencv实现中为黑色-白色)。Haar特征值反映了图像的灰度变化情况。例如:脸部的一些特征能由矩形特征简单的描述,如:眼睛要比脸颊颜色要深,鼻梁两侧比鼻梁颜色要深,嘴巴比周围颜色要深等。但矩形特征只对一些简单的图形结构,如边缘、线段较敏感,所以只能描述特定走向(水平、垂直、对角)的结构。
2.矩形特征个数的计算
在实际中,Haar特征可以在检测窗口中由放大+平移产生一系列子特征,但是白:黑区域面积比始终保持不变。那么这些通过放大+平移的获得的子特征到底总共有多少个?Rainer Lienhart在他的论文中给出了完美的解释:假设检测窗口大小为W*H,矩形特征大小为w*h,X和Y为表示矩形特征在水平和垂直方向的能放大的最大比例系数:。在检测窗口Window中,一般矩形特征(upright rectangle)的数量为:
3.积分图
当有了大量的矩形特征用于训练和检测时,接下来的问题是如何计算Haar特征值。Viola等人提出了利用积分图求特征值的方法。一个区域的像素值,可以利用该区域的端点的积分图来計算。在积分图中,ii(1)表示区域A的像素值,ii(2)表示区域A+B的像素值,ii(3)表示区域A+C的像素值,ii(4) 表示区域A+B+C+D的像素值。而:
区域D的像素值=区域A+B+C+D的像素值+区域A的像素值-区域A+B的像素值-区域A+C的像素值.
即:
区域D的像素值=ii(4) + ii(1) - ii(2) - ii(3)
由此,可用积分图快速得到一个区域的像素值。
4.Adaboost分类器
在确定了训练子窗口中的矩形特征数量和特征值后,需要对每一个特征,训练一个弱分类器。Adaboost算法基本原理就是将多个弱分类器(弱分类器一般选用单层决策树)进行合理的结合,使其成为一个强分类器。具体说来,整个Adaboost迭代算法分为3步:
(1)初始化训练数据的权值分布。如果有N个样本,则每一个训练样本最开始时都被赋予相同的权重:1/N。
(2)训练弱分类器。具体训练过程中,如果某个样本点已经被准确地分类,那么在构造下一个训练集中,它的权重就被降低;相反,如果某个样本点没有被准确地分类,那么它的权重就得到提高。然后,权重更新过的样本集被用于训练下一个分类器,整个训练过程如此迭代地进行下去。
(3)将各个训练得到的弱分类器组合成强分类器。各个弱分类器的训练过程结束后,加大分类误差率小的弱分类器的权重,使其在最终的分类函数中起着较大的决定作用,而降低分类误差率大的弱分类器的权重,使其在最终的分类函数中起着较小的决定作用。换言之,误差率低的弱分类器在最终分类器中占的权重较大,否则较小。
(二)卷积神经网络
1.输入层
在处理图像的卷积神经网络中,它一般代表了一张图片的像素矩阵。通常为(length * width *channel)。 三维矩阵的深度代表了图像的彩色通道(channel)。比如黑白图片的深度为1,而在RGB色彩模式下,图像的深度为3。从输入层开始,卷积神经网络通过不同的神经网络结构将上一层的三维矩阵转化为下一层的三维矩阵,直到最后的全连接层。
2.卷积层
卷积层主要进行的操作是对图片进行特征提取,随着卷积层的深入它提取到的特征就越高级。对于一张输入图片,将其转化为矩阵,矩阵的元素为对应的像素值,对于一张大小为5×5的图像,使用3×3的感受野进行移动长度为1的非零填充卷积,可以得到大小为3×3的特征平面,此后卷积核会先向右移动,再向下移动,直到最后和每一个值完成了运算。每当图像进行了一次卷积之后,它的输出都会发生对应的改变。若输入为5x5,在尺寸为3x3的卷积核和步长为1的作用下,最后得到的输出图像特征的尺寸不再是5,而是5-3+1=3。所以经过了卷积层之后,输出尺寸会发生相应的变化。 3.池化层
池化层的作用是把卷积层得到的特征平面的数据量降低。池化之后的图像大小虽然发生了变化,但是图像的大致轮廓并没有丢失,而且生成的平面作为下次卷积的输入,在卷积核不变的情况下相当于增加了卷积核对于图片信息的提取能力。池化有平均值池化和最大值池化,最大池化层(max pooling)使用最大值操作,是被使用得最多的池化层结构。
三、实现过程
(一)gain_face.py(截取人脸图像)
该脚本主要运用OpenCV来获取人脸图像,图片来源可以是一段保存好的视频,也可以通过USB摄像头实时捕捉。若通过摄像头捕捉人脸,则需预先设定图片捕捉数量,询问用户姓名。cv2.CascadeClassifier("E:\haarcascade_frontalface_alt2.xml")告诉OpenCV使用人脸识别分类器(给定haarcascade_frontalface_alt2.xml的路径),然后循环从视频里读取一帧数据,调用cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)将当前帧转换为灰度图像,图像灰度化后可以降低计算量,便于后面计算特征,然后调用classfier.detectMultiScale(grey, scaleFactor=1.2, minNeighbors=2, minSize=(32, 32))进行人脸检测,其中scaleFactor=1.2是图像缩放比例, minNeighbors=2为两个检测有效点,这样OpenCV截取的人脸灰度图将会保存到以各姓名命名的文件夹下,当达到我们设定的图片数量后,程序会退出循环并销毁摄像头。
(二)load_dataset.py(图像数据预处理)
上一步我们得到了不同的人的人脸灰度图,这一步就是来处理这些灰度图像。过程中调用了cv2.resize(constant_image,(height,width))来统一图片大小,将所有图片的规格统一成了64x64。考虑两个数组,一个是数据集,另一个是标注集,数据集存放处理过后的图像,标记集存放图像路径,最后为每一类图像(每一个人)指定一个唯一的标签,便于后面训练。
(三)face_train.py(模型训练)
1.准备训练数据
首先导入训练需要的库TensorFlow和Keras,TensorFlow的版本我们选择1.13.1,然后定义一个数据加载类,用于准备训练数据,在这个类里我们设置了训练集、验证集和测试集, 然后导入load_dataset.py的方法,将上一步处理过的图片加载到这三个集中。这一步的代码为train_images, valid_images, train_labels,valid_labels=train_test_split(images,labels,test_size=0.3,random_state=random.randint(0, 100)),然后根据keras库要求的维度顺序重组训练数据集,为减少计算量,我们将像素进行归一化处理,代码为:train_images /= 255
valid_images /= 255
test_images /= 255
2.搭建CNN网络模型
到现在为止,训练数据就准备完成了。接下来开始搭建CNN网络模型,我们用model = Sequential()构建一个空的网络模型,它是一个线性堆叠模型,各神经网络层会被顺序添加,然后顺序地添加CNN网络需要的各层,部分代码为:
model.add(Convolution2D(32, 3, 3, border_mode='same',
input_shape=dataset.input_shape)) # 1 2维卷积层: 32个过滤器,每个像素是3x3
model.add(Activation('relu')) # 2 激活函数层
model.add(MaxPooling2D(pool_size=(2, 2))) # 3 池化层
model.add(Dropout(0.25)) # 4 Dropout层
model.add(Convolution2D(64, 3, 3, border_mode='same')) # 5 2维卷积层
model.add(Activation('relu')) # 6 激活函数层
model.add(Flatten()) # 7 Flatten层
model.add(Dense(512)) # 8 全连接层
model.add(Activation('relu')) # 9 激活函数层
model.add(Dropout(0.5)) # 10 Dropout层
model.add(Dense(nb_classes)) # 11 全连接层
model.add(Activation('softmax')) # 12 分类层 输出最终结果
3.开始训练
模型搭建后,接下来就开始训练了。定义一个训练函数def train(),采用SGD+momentum的优化器進行训练,生成一个优化器对象,这里代码为sgd = SGD(lr=0.01,decay=1e-6,momentum=0.9,nesterov=True),用model.compile(loss='categorical_crossentropy',optimizer=sgd,metrics=['accuracy'])完成实际的模型配置工作,然后用model.fit_generator()构建生成器训练模型,训练完成后将会生成一个aggregate.face.model.h5文件,该文件就是后面人脸识别时的判决模型。 (四)face_recongnition.py(识别人脸)
现在我们已经有了训练成熟的模型,在这个脚本里,首先导入aggregate.face.model.h5模型,然后利用OpenCV打开摄像头捕捉人脸,在一系列灰度处理、像素处理后,将获得的实时人脸图片与导入的模型进行对比,最后给出文字提示这是谁。部分代码为:
image = frame[y: y + h, x: x + w]
faceID = model.face_predict(image) # 截取脸部图像提交给模型
cv2.putText() # 给出文字提示
四、结语
本系统设计源于生活,有很好的实用性。项目的重点有二,一是图像数据的处理,二是CNN模型的训练。在数据处理中,必须将人脸图像灰度化,否则计算强度很大,效率将大幅度降低;图片的规格要统一,像素要归一化处理,这样才能最大化计算效率,训练精度也会提高。模型训练是此项目的重中之重,由于项目初衷在于实现任意数量人脸的识别,所以这里设定了多层卷积层和池化层,目的是提高训练精度。训练过程中,训练数量是一个值得考虑的因素,太少则达不到训练效果,太多则会出现训练过拟合现象,但只要经过多次测试,找到合适的训练数量,就能达到一个较为理想的训练效果。
【参考文献】
[1]许佳胜,李欣,孙宏凯. 人脸识别技术概述[J].科技风.2020(04)
[2]党永成. 人脸识别技术综述及分析[J].电子技术与软件工程.2018(03)
[3]景晨凯,宋涛,庄雷. 基于深度卷积神经网络的人脸识别技术综述[J].计算机应用与软件.2018(01)
[4]张延安,王宏玉,徐方. 基于深度卷积神经网络与中心损失的人脸识别[J].科学技术与工程.2017(35)
[5]陈华官. 基于端到端深度卷积神经网络的人脸识别算法[D].浙江大学.2017
[6]黄发扬. 浅谈基于神经网络深度学习算法的人脸识别技术[J].智能建 筑.2018(10)
[7]張广才,何继荣,高文朋. 基于深度学习的人脸识别研究[J].无线互联科技.2019(19)
[8]徐政超. 基于深度学习的人脸识别技术研究[J].信息系统工程.2019(10).
【关键词】深度学习;人脸识别;卷积神经网络;OpenCV;TensorFlow
人脸识别本质是用一个几何特征矢量来表示人脸,并根据模式识别中层次聚类的思想设计分类器,达到识别目的。调用OpenCV库中的功能函数来截取视频中的图像帧数据,并进行一系列预处理,完成图片的灰度化以及统一图片的大小和格式,然后再将这些图片输入到搭建好的卷积神经网络中进行训练,训练完成后将生成一个训练模型,此模型便是人脸识别时的评估标准。
一、模块功能及结构划分
系统共分为四个部分,分别为:实时人脸截取模块、图片预处理模块、CNN搭建和训练模块以及人脸检测模块。
实时人脸截取模块主要负责采集人脸图片。管理员输入要采集的人员姓名,后台生成以该姓名为名称的文件夹,然后使用USB摄像头获取视频数据,利用OpenCV的功能函数定位人脸部分,截取一帧的图像数据保存到该文件夹下,当采集数量达到设定的数量后,摄像头关闭。
图片预处理模块主要负责图片灰度化、像素归一化、图片大小规格化以及为每一类图片夹指定一个唯一的标签,便于后面的训练。
CNN搭建和训练模块主要完成搭建神经网络、划分训练集和验证集、深度学习训练以及训练模型的保存,有了训练模型后就能进行人脸识别了。
人脸检测模块主要调用摄像头来获取人脸图片,读入之前训练成熟的网路模型来进行人脸识别。
二、项目原理
(一)人脸识别分类器
1.Haar特征
Haar特征分为三类:边缘特征、线性特征、中心特征和对角线特征,组合成特征模板。特征模板内有白色和黑色两种矩形,并定义该模板的特征值为白色矩形像素和减去黑色矩形像素和(在opencv实现中为黑色-白色)。Haar特征值反映了图像的灰度变化情况。例如:脸部的一些特征能由矩形特征简单的描述,如:眼睛要比脸颊颜色要深,鼻梁两侧比鼻梁颜色要深,嘴巴比周围颜色要深等。但矩形特征只对一些简单的图形结构,如边缘、线段较敏感,所以只能描述特定走向(水平、垂直、对角)的结构。
2.矩形特征个数的计算
在实际中,Haar特征可以在检测窗口中由放大+平移产生一系列子特征,但是白:黑区域面积比始终保持不变。那么这些通过放大+平移的获得的子特征到底总共有多少个?Rainer Lienhart在他的论文中给出了完美的解释:假设检测窗口大小为W*H,矩形特征大小为w*h,X和Y为表示矩形特征在水平和垂直方向的能放大的最大比例系数:。在检测窗口Window中,一般矩形特征(upright rectangle)的数量为:
3.积分图
当有了大量的矩形特征用于训练和检测时,接下来的问题是如何计算Haar特征值。Viola等人提出了利用积分图求特征值的方法。一个区域的像素值,可以利用该区域的端点的积分图来計算。在积分图中,ii(1)表示区域A的像素值,ii(2)表示区域A+B的像素值,ii(3)表示区域A+C的像素值,ii(4) 表示区域A+B+C+D的像素值。而:
区域D的像素值=区域A+B+C+D的像素值+区域A的像素值-区域A+B的像素值-区域A+C的像素值.
即:
区域D的像素值=ii(4) + ii(1) - ii(2) - ii(3)
由此,可用积分图快速得到一个区域的像素值。
4.Adaboost分类器
在确定了训练子窗口中的矩形特征数量和特征值后,需要对每一个特征,训练一个弱分类器。Adaboost算法基本原理就是将多个弱分类器(弱分类器一般选用单层决策树)进行合理的结合,使其成为一个强分类器。具体说来,整个Adaboost迭代算法分为3步:
(1)初始化训练数据的权值分布。如果有N个样本,则每一个训练样本最开始时都被赋予相同的权重:1/N。
(2)训练弱分类器。具体训练过程中,如果某个样本点已经被准确地分类,那么在构造下一个训练集中,它的权重就被降低;相反,如果某个样本点没有被准确地分类,那么它的权重就得到提高。然后,权重更新过的样本集被用于训练下一个分类器,整个训练过程如此迭代地进行下去。
(3)将各个训练得到的弱分类器组合成强分类器。各个弱分类器的训练过程结束后,加大分类误差率小的弱分类器的权重,使其在最终的分类函数中起着较大的决定作用,而降低分类误差率大的弱分类器的权重,使其在最终的分类函数中起着较小的决定作用。换言之,误差率低的弱分类器在最终分类器中占的权重较大,否则较小。
(二)卷积神经网络
1.输入层
在处理图像的卷积神经网络中,它一般代表了一张图片的像素矩阵。通常为(length * width *channel)。 三维矩阵的深度代表了图像的彩色通道(channel)。比如黑白图片的深度为1,而在RGB色彩模式下,图像的深度为3。从输入层开始,卷积神经网络通过不同的神经网络结构将上一层的三维矩阵转化为下一层的三维矩阵,直到最后的全连接层。
2.卷积层
卷积层主要进行的操作是对图片进行特征提取,随着卷积层的深入它提取到的特征就越高级。对于一张输入图片,将其转化为矩阵,矩阵的元素为对应的像素值,对于一张大小为5×5的图像,使用3×3的感受野进行移动长度为1的非零填充卷积,可以得到大小为3×3的特征平面,此后卷积核会先向右移动,再向下移动,直到最后和每一个值完成了运算。每当图像进行了一次卷积之后,它的输出都会发生对应的改变。若输入为5x5,在尺寸为3x3的卷积核和步长为1的作用下,最后得到的输出图像特征的尺寸不再是5,而是5-3+1=3。所以经过了卷积层之后,输出尺寸会发生相应的变化。 3.池化层
池化层的作用是把卷积层得到的特征平面的数据量降低。池化之后的图像大小虽然发生了变化,但是图像的大致轮廓并没有丢失,而且生成的平面作为下次卷积的输入,在卷积核不变的情况下相当于增加了卷积核对于图片信息的提取能力。池化有平均值池化和最大值池化,最大池化层(max pooling)使用最大值操作,是被使用得最多的池化层结构。
三、实现过程
(一)gain_face.py(截取人脸图像)
该脚本主要运用OpenCV来获取人脸图像,图片来源可以是一段保存好的视频,也可以通过USB摄像头实时捕捉。若通过摄像头捕捉人脸,则需预先设定图片捕捉数量,询问用户姓名。cv2.CascadeClassifier("E:\haarcascade_frontalface_alt2.xml")告诉OpenCV使用人脸识别分类器(给定haarcascade_frontalface_alt2.xml的路径),然后循环从视频里读取一帧数据,调用cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)将当前帧转换为灰度图像,图像灰度化后可以降低计算量,便于后面计算特征,然后调用classfier.detectMultiScale(grey, scaleFactor=1.2, minNeighbors=2, minSize=(32, 32))进行人脸检测,其中scaleFactor=1.2是图像缩放比例, minNeighbors=2为两个检测有效点,这样OpenCV截取的人脸灰度图将会保存到以各姓名命名的文件夹下,当达到我们设定的图片数量后,程序会退出循环并销毁摄像头。
(二)load_dataset.py(图像数据预处理)
上一步我们得到了不同的人的人脸灰度图,这一步就是来处理这些灰度图像。过程中调用了cv2.resize(constant_image,(height,width))来统一图片大小,将所有图片的规格统一成了64x64。考虑两个数组,一个是数据集,另一个是标注集,数据集存放处理过后的图像,标记集存放图像路径,最后为每一类图像(每一个人)指定一个唯一的标签,便于后面训练。
(三)face_train.py(模型训练)
1.准备训练数据
首先导入训练需要的库TensorFlow和Keras,TensorFlow的版本我们选择1.13.1,然后定义一个数据加载类,用于准备训练数据,在这个类里我们设置了训练集、验证集和测试集, 然后导入load_dataset.py的方法,将上一步处理过的图片加载到这三个集中。这一步的代码为train_images, valid_images, train_labels,valid_labels=train_test_split(images,labels,test_size=0.3,random_state=random.randint(0, 100)),然后根据keras库要求的维度顺序重组训练数据集,为减少计算量,我们将像素进行归一化处理,代码为:train_images /= 255
valid_images /= 255
test_images /= 255
2.搭建CNN网络模型
到现在为止,训练数据就准备完成了。接下来开始搭建CNN网络模型,我们用model = Sequential()构建一个空的网络模型,它是一个线性堆叠模型,各神经网络层会被顺序添加,然后顺序地添加CNN网络需要的各层,部分代码为:
model.add(Convolution2D(32, 3, 3, border_mode='same',
input_shape=dataset.input_shape)) # 1 2维卷积层: 32个过滤器,每个像素是3x3
model.add(Activation('relu')) # 2 激活函数层
model.add(MaxPooling2D(pool_size=(2, 2))) # 3 池化层
model.add(Dropout(0.25)) # 4 Dropout层
model.add(Convolution2D(64, 3, 3, border_mode='same')) # 5 2维卷积层
model.add(Activation('relu')) # 6 激活函数层
model.add(Flatten()) # 7 Flatten层
model.add(Dense(512)) # 8 全连接层
model.add(Activation('relu')) # 9 激活函数层
model.add(Dropout(0.5)) # 10 Dropout层
model.add(Dense(nb_classes)) # 11 全连接层
model.add(Activation('softmax')) # 12 分类层 输出最终结果
3.开始训练
模型搭建后,接下来就开始训练了。定义一个训练函数def train(),采用SGD+momentum的优化器進行训练,生成一个优化器对象,这里代码为sgd = SGD(lr=0.01,decay=1e-6,momentum=0.9,nesterov=True),用model.compile(loss='categorical_crossentropy',optimizer=sgd,metrics=['accuracy'])完成实际的模型配置工作,然后用model.fit_generator()构建生成器训练模型,训练完成后将会生成一个aggregate.face.model.h5文件,该文件就是后面人脸识别时的判决模型。 (四)face_recongnition.py(识别人脸)
现在我们已经有了训练成熟的模型,在这个脚本里,首先导入aggregate.face.model.h5模型,然后利用OpenCV打开摄像头捕捉人脸,在一系列灰度处理、像素处理后,将获得的实时人脸图片与导入的模型进行对比,最后给出文字提示这是谁。部分代码为:
image = frame[y: y + h, x: x + w]
faceID = model.face_predict(image) # 截取脸部图像提交给模型
cv2.putText() # 给出文字提示
四、结语
本系统设计源于生活,有很好的实用性。项目的重点有二,一是图像数据的处理,二是CNN模型的训练。在数据处理中,必须将人脸图像灰度化,否则计算强度很大,效率将大幅度降低;图片的规格要统一,像素要归一化处理,这样才能最大化计算效率,训练精度也会提高。模型训练是此项目的重中之重,由于项目初衷在于实现任意数量人脸的识别,所以这里设定了多层卷积层和池化层,目的是提高训练精度。训练过程中,训练数量是一个值得考虑的因素,太少则达不到训练效果,太多则会出现训练过拟合现象,但只要经过多次测试,找到合适的训练数量,就能达到一个较为理想的训练效果。
【参考文献】
[1]许佳胜,李欣,孙宏凯. 人脸识别技术概述[J].科技风.2020(04)
[2]党永成. 人脸识别技术综述及分析[J].电子技术与软件工程.2018(03)
[3]景晨凯,宋涛,庄雷. 基于深度卷积神经网络的人脸识别技术综述[J].计算机应用与软件.2018(01)
[4]张延安,王宏玉,徐方. 基于深度卷积神经网络与中心损失的人脸识别[J].科学技术与工程.2017(35)
[5]陈华官. 基于端到端深度卷积神经网络的人脸识别算法[D].浙江大学.2017
[6]黄发扬. 浅谈基于神经网络深度学习算法的人脸识别技术[J].智能建 筑.2018(10)
[7]張广才,何继荣,高文朋. 基于深度学习的人脸识别研究[J].无线互联科技.2019(19)
[8]徐政超. 基于深度学习的人脸识别技术研究[J].信息系统工程.2019(10).