由于图床过期,图片无法正常显示,有图阅览请移步以下Gitee/Github网址,文末获取【源码和部署教程】或者通过以下Gitee/Github的文末邮件获取

Gitee(推荐国内访问): https://gitee.com/qunmasj/projects

Github(推荐国外访问): https://github.com/qunshansj?tab=repositories



1.研究背景与意义

随着计算机视觉技术的不断发展,人脸检测系统在许多领域中起着重要的作用。人脸检测是计算机视觉中的一个基本问题,它可以用于人脸识别、人脸表情分析、人脸姿态估计等应用。人脸检测系统的目标是在图像或视频中准确地检测出人脸的位置和边界框。

传统的人脸检测方法主要基于特征工程和机器学习算法,如Haar特征和AdaBoost算法。这些方法在一定程度上能够实现人脸检测的任务,但是存在一些问题。首先,传统方法需要手动设计特征,这需要大量的人力和时间成本。其次,传统方法对于光照、尺度变化和姿态变化等因素的鲁棒性较差。最后,传统方法的检测速度较慢,难以满足实时应用的需求。

基于卷积神经网络(Convolutional Neural Network,CNN)的人脸检测系统在解决上述问题方面具有很大的优势。CNN是一种深度学习模型,它能够自动学习图像的特征表示,避免了手动设计特征的过程。此外,CNN具有较强的非线性建模能力,能够更好地处理光照、尺度和姿态变化等问题。最重要的是,CNN可以通过并行计算来加速人脸检测的过程,实现实时性能。

基于卷积神经网络的人脸检测系统已经取得了显著的成果。一些经典的CNN模型,如AlexNet、VGGNet和ResNet等,已经在人脸检测任务上取得了很好的效果。这些模型通过多层卷积和池化操作,逐渐提取图像的高级特征,并通过全连接层进行分类和回归。此外,一些改进的CNN模型,如SSD(Single Shot MultiBox Detector)和YOLO(You Only Look Once)等,进一步提高了人脸检测的准确性和速度。

基于卷积神经网络的人脸检测系统在实际应用中具有广泛的应用前景。首先,人脸检测系统可以应用于人脸识别技术,用于身份验证和安全控制。其次,人脸检测系统可以应用于人脸表情分析,用于情感识别和心理研究。此外,人脸检测系统还可以应用于人脸姿态估计,用于虚拟现实和增强现实等领域。

总之,基于卷积神经网络的人脸检测系统在计算机视觉领域具有重要的研究意义和应用价值。通过深度学习模型的自动特征学习和并行计算的加速优势,基于卷积神经网络的人脸检测系统能够实现准确、鲁棒和实时的人脸检测任务,为人脸识别、人脸表情分析和人脸姿态估计等应用提供了有力的支持。未来的研究方向包括进一步提高人脸检测系统的准确性和速度,以及应用于更广泛的领域和场景中。

2.图片演示

2.jpg

3.jpg

3.视频演示

4.Adam 优化

参考该博客提出的算法改进方案,不难看出优化算法之间的联系。对于神经网络训练,最初使用的是固定学习率的梯度下降法。但是梯度下降法的训练速度比较慢,为了加快训练发展出了随机梯度下降法和动量随机梯度下降法。SGD 以及其变种在进行网络训练时使用同一学习率对所有的参数进行更新,但是神经网络中往往包含了大量的参数,所以学习率的设置需要大量的测试实验才能找到合适学习率。为了更加贴合深度学习的复杂模型的训练,每个参数设置不同学习率的自适应学习率的优化算法被提出,比如说AdaGrad 算法。为解决AdaGrad 算法累积历史梯度平方造成的学习率过早或者过量的减少,带有指数加权平均的RMSProp算法被提了出来。随后进一步融合了RMSProp算法和动量思想的Adam也被提了出来。
Adam优化算法的收敛速度虽然比较快,但是其收敛结果却并不一定令人满意。在Keskar的文献l53中,作者在 CIFAR-10数据集上进行测试,Adam 的收敛速度确实要比SGD要快,但是最终收敛的结果并没有SGD好。该博客中提到Adam算法可能会错过全局最优解。关于Adam 优化算法的动态学习率的争议一直存在。所以本文针对Adam优化算法的动态学习率进行了分析研究并提出了一种改进算法。Adam 的学习率受到二阶矩的影响,二阶矩是固定时间窗口内的累积,随着时间窗口的变化,遇到的数据可能发生巨变,造成学习率时大时小不单调变化。这就可能在训练后期引起学习率的震荡,最糟的情况会导致模型无法收敛。改进算法中针对这一问题修改了修正二阶矩的偏差的公式,使得改进算法的步长在训练后期相对Adam来说单调递减。此外改进算法还引入了Momentum动量的变种Nesterov动量。接下来我们详细阐述本文的改进算法。
image.png
Momentum动量的主要思想主要来借鉴于物理学中的动量概念,来源该博客提出的定义,模拟出的是物体运动时的惯性,深度学习中训练的应用中就是,在更新参数就时候在一定程度上保留之前更新的方向,同时利用当前mini-batch 的梯度进行微调至最终的更新方向,这样便可以在一定程度上增加稳定性,从而能够更快的训练网络模型,并且有一定程度上摆脱局部最优的能力。
引入动量的目的就是为了加快深度学习中模型的学习训练过程,尤其是对于一些曲率高或者噪声比较大的梯度能够比较好的提高训练速度,动量的主要思想是积累了之前梯度指数加权平均。关于Momentum动量我们可以用下图帮助理解。
image.png

5.实时人脸识别流程

整个实时人脸识别系统包含人脸数据采集模块,人脸图像处理模块,网络训练模块以及人脸识别模块。其中人脸采集模块主要负责从视频中或者图像中检测出人脸,人脸检测使用的是OpenCV库,同时可以保存图像用作下一步人脸图像处理。人脸图像处理模块主要功能是将图像中人脸截取出来,然后将图像灰度直方化,处理成统一的64*64大小的图像,将人脸图像放入深度生成对抗网络中进行生成图像,扩充数据集。网络训练模块的主要作用是构建基于卷积神经网络人脸识别的模型,将数据集输入进而训练能够进行识别的网络,同时会将训练好的模型的参数进行保存,以用于进行人脸识别时使用。人脸识别模块的主要功能是开启笔记本摄像头,进行实时的识别,将每一帧图像都放入人脸数据采集模块,若识别出人脸则转入人脸图像处理模块,将图像进行处理截取出人脸并将其灰度直方化,然后调取保存好的网络参数,将图像放入卷积神经网络模型中进行识别,若识别出则在实时视频中将识别出的人脸用方框框出,并标记上被识别出人的姓名。
整个系统的设计流程如下:
(1)图像预处理阶段,首先通过人脸识别模块识将图片或者视频检测出人脸,然后用人脸图像处理模块进行人脸截取和图像处理,得到统一大小的人脸图像。
(2)将数据集放入LECNN中进行训练,训练优化算法采用第四章改进算法,训练完成后保存参数。
(3)对实时视频进行人脸识别,通过人脸数据采集模块和人脸图像处理模块得到需要识别的人脸图像,调取网络参数,将人脸图像输入至卷积神经网络进行识别,返回识别结果。如若识别成功则将识别出的人脸框出并标注姓名。
系统的流程图如图所示
image.png

6.核心代码讲解

6.1 config.py

根据给定的代码,可以将其封装为一个名为EmotionDetection的类,如下所示:

1
2
3
class FaceRecognition:
def __init__(self):
self.path_images = "images_db"

这样,我们可以通过创建EmotionDetection和FaceRecognition的实例来访问这些变量。

这个程序文件名为config.py,主要用于配置一些参数和路径。
在face_recognition部分,定义了图片文件夹的路径为”images_db”。

6.2 deep_face.py

以下是封装为类的代码:

1
2
3
4
5
6
7
8
9
10

class FaceAnalyzer:
def __init__(self, image_path):
self.image_path = image_path
self.demography = None

def analyze(self):
self.demography = DeepFace.analyze(self.image_path, actions=['age', 'gender', 'race', 'emotion'])
...

这个类封装了人脸分析功能,通过analyze方法分析图像中的人脸,然后可以通过get_ageget_genderget_emotionget_race方法获取分析结果。

这个程序文件名为deep_face.py,它使用了deepface库。该程序通过分析人脸图像来获取人物的年龄、性别、种族和情绪信息。在这个例子中,它分析了名为”juan.jpg”的图像。程序输出了分析结果。

6.3 demo.py

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

class FaceRecognition:
def __init__(self):
self.detector = dlib.get_frontal_face_detector()
self.predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")
self.sess = tf.Session()
saver = tf.train.import_meta_graph('model.meta')
saver.restore(self.sess, tf.train.latest_checkpoint('./'))


def get_face_info(self, frame):
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
faces = self.detector(gray)
face_info = []
for face in faces:
landmarks = self.predictor(gray, face)
face_info.append(landmarks)
return face_info

def bounding_box(self, face_info, frame):
for face in face_info:
x1 = face.left()
y1 = face.top()
x2 = face.right()
y2 = face.bottom()
cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 3)
return frame

def recognize_face(self, frame):
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
faces = self.detector(gray)
for face in faces:
landmarks = self.predictor(gray, face)
face_array = np.array(landmarks)
face_array = np.expand_dims(face_array, axis=0)
...

这个程序文件名为demo.py,主要功能是使用深度学习模型进行人脸识别。程序导入了一些必要的库和模块,包括f_Face_info、cv2、time、imutils、argparse、numpy、PyQt5、os、sys、pathlib、tensorflow、dlib、sklearn等。

程序定义了一些类和函数,包括SPP、ChannelAttention、SpatialAttention、getPaddingSize、cnnLayer等。这些类和函数用于构建深度学习模型和进行人脸识别的相关操作。

程序的主要逻辑是读取一张人脸图片,然后使用深度学习模型对人脸进行识别和预测。程序中还包含了一些参数的定义和模型的保存和加载操作。

最后,程序通过调用f_Face_info模块中的函数对人脸进行检测和绘制边界框,并输出人脸信息。

6.4 faces_my.py

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

class FaceDatasetCollector:
def __init__(self, faces_my_path='./faces_my', size=64):
self.faces_my_path = faces_my_path
self.size = size
if not os.path.exists(self.faces_my_path):
os.makedirs(self.faces_my_path)

def img_change(self, img, light=1, bias=0):
width = img.shape[1]
height = img.shape[0]
for i in range(0, width):
for j in range(0, height):
for k in range(3):
tmp = int(img[j, i, k]*light + bias)
if tmp > 255:
tmp = 255
elif tmp < 0:
tmp = 0
img[j,i,k] = tmp
return img

def collect_dataset(self):
detector = dlib.get_frontal_face_detector()
cap = cv2.VideoCapture(0)

num = 1
while True:
if (num <= 10000):
print('Being processed picture %s' % num)
success, img = cap.read()
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
dets = detector(gray_img, 1)
for i, d in enumerate(dets):
x1 = d.top() if d.top() > 0 else 0
y1 = d.bottom() if d.bottom() > 0 else 0
x2 = d.left() if d.left() > 0 else 0
y2 = d.right() if d.right() > 0 else 0

face = img[x1:y1,x2:y2]
face = self.img_change(face, random.uniform(0.5, 1.5), random.randint(-50, 50))
face = cv2.resize(face, (self.size,self.size))
cv2.imshow('image', face)
cv2.imwrite(self.faces_my_path+'/'+str(num)+'.jpg', face)
num += 1
key = cv2.waitKey(30)
if key == 27:
break
else:
print('Finished!')
break

程序会通过摄像头实时获取图像,并使用特征提取器进行人脸检测。检测到人脸后,会对人脸进行亮度和对比度的调整,并将人脸图像保存到指定的文件夹中。程序会一直运行,直到采集到10000张人脸图像为止。

6.5 faces_other.py

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

class FaceDataCollector:
def __init__(self, source_path, faces_other_path, size=64):
self.source_path = source_path
self.faces_other_path = faces_other_path
self.size = size
self.detector = dlib.get_frontal_face_detector()
self.num = 1

def collect_face_data(self):
if not os.path.exists(self.faces_other_path):
os.makedirs(self.faces_other_path)

for (path, dirnames, filenames) in os.walk(self.source_path):
for filename in filenames:
if filename.endswith('.jpg'):
print('Being processed picture %s' % self.num)
img_path = os.path.join(path, filename)
img = cv2.imread(img_path)
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
dets = self.detector(gray_img, 1)

for i, d in enumerate(dets):
x1 = d.top() if d.top() > 0 else 0
y1 = d.bottom() if d.bottom() > 0 else 0
x2 = d.left() if d.left() > 0 else 0
y2 = d.right() if d.right() > 0 else 0

face = img[x1:y1, x2:y2]
face = cv2.resize(face, (self.size, self.size))
cv2.imshow('image', face)
cv2.imwrite(os.path.join(self.faces_other_path, str(self.num) + '.jpg'), face)
self.num += 1

key = cv2.waitKey(30)
if key == 27:
sys.exit(0)

这个程序文件是用来采集其他人脸数据集的。它首先下载了一个人脸数据集,并将下载的图片放在img_source目录下。然后使用dlib库来批量识别图片中的人脸部分,并将识别到的人脸保存到指定目录faces_other。识别到的人脸大小为64*64像素。程序使用了dlib自带的frontal_face_detector作为特征提取器来进行人脸检测。程序会遍历img_source目录下的所有图片文件,并对每张图片进行人脸检测和保存。最后,程序会显示每张检测到的人脸图片,并等待按下ESC键退出程序。

6.6 faces_train.py

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

class CNNModel:
def __init__(self, faces_my_path, faces_other_path, batch_size, learning_rate, size):
self.faces_my_path = faces_my_path
self.faces_other_path = faces_other_path
self.batch_size = batch_size
self.learning_rate = learning_rate
self.size = size
self.imgs = []
self.labs = []
self.train_x = None
self.test_x = None
self.train_y = None
self.test_y = None
self.num_batch = None
self.x = None
self.y_ = None
self.keep_prob_fifty = None
self.keep_prob_seventy_five = None
self.out = None
self.cross_entropy = None
self.optimizer = None
self.accuracy = None
self.merged_summary_op = None
self.saver = None

def readData(self, path, h, w):
for filename in os.listdir(path):
if filename.endswith('.jpg'):
filename = path + '/' + filename
img = cv2.imread(filename)
top, bottom, left, right = self.getPaddingSize(img)
img = cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT, value=[0, 0, 0])
img = cv2.resize(img, (h, w))
self.imgs.append(img)
self.labs.append(path)

def getPaddingSize(self, img):
height, width, _ = img.shape
top, bottom, left, right = (0, 0, 0, 0)
longest = max(height, width)

if width < longest:
tmp = longest - width
left = tmp // 2
right = tmp - left
elif height < longest:
tmp = longest - height
top = tmp // 2
bottom = tmp - top
else:
pass
return top, bottom, left, right

def cnnLayer(self):
W1 = tf.Variable(tf.random_normal([3, 3, 3, 32]))
b1 = tf.Variable(tf.random_normal([32]))
conv1 = tf.nn.relu(tf.nn.conv2d(self.x, W1, strides=[1, 1, 1, 1], padding='SAME')+b1)
pool1 = tf.nn.max_pool(conv1, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
drop1 = tf.nn.dropout(pool1, self.keep_prob_fifty)

W2 = tf.Variable(tf.random_normal([3, 3, 32, 64]))
b2 = tf.Variable(tf.random_normal([64]))
conv2 = tf.nn.relu(tf.nn.conv2d(drop1, W2, strides=[1, 1, 1, 1], padding='SAME') + b2)
pool2 = tf.nn.max_pool(conv2, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
drop2 = tf.nn.dropout(pool2, self.keep_prob_fifty)

W3 = tf.Variable(tf.random_normal([3, 3, 64, 64]))
b3 = tf.Variable(tf.random_normal([64]))
conv3 = tf.nn.relu(tf.nn.conv2d(drop2, W3, strides=[1, 1, 1, 1], padding='SAME') + b3)
pool3 = tf.nn.max_pool(conv3, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
drop3 = tf.nn.dropout(pool3, self.keep_prob_fifty)

Wf = tf.Variable(tf.random_normal([8*8*64,512]))
bf = tf.Variable(tf.random_normal([512]))
drop3_flat = tf.reshape(drop3, [-1, 8*8*64])
dense = tf.nn.relu(tf.matmul(drop3_flat, Wf) + bf)
dropf = tf.nn.dropout(dense, self.keep_prob_seventy_five)

Wout = tf.Variable(tf.random_normal([512,2]))
bout = tf.Variable(tf.random_normal([2]))
out = tf.add(tf.matmul(dropf, Wout), bout)
return out

def train(self):
self.out = self.cnnLayer()
self.cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=self.out, labels=self.y_))
self.optimizer = tf.train.AdamOptimizer(self.learning_rate).minimize(self.cross_entropy)
self.accuracy = tf.reduce_mean(tf.cast(tf.equal(tf.argmax(self.out, 1), tf.argmax(self.y_, 1)), tf.float32))
tf.summary.scalar('loss', self.cross_entropy)
tf.summary.scalar('accuracy', self.accuracy)
self.merged_summary_op = tf.summary.merge_all()
self.saver = tf.train.Saver()
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
summary_writer = tf.summary.FileWriter('./tmp', graph=tf.get_default_graph())
for n in range(10):
for i in range(self.num_batch):
batch_x = self.train_x[i*self.batch_size: (i+1)*self.batch_size]
batch_y = self.train_y[i*self.batch_size: (i+1)*self.batch_size]
_, loss, summary = sess.run([self.optimizer, self.cross_entropy, self.merged_summary_op],
feed_dict={self.x: batch_x, self.y

该程序文件名为faces_train.py,主要功能是使用卷积神经网络(CNN)对人脸进行分类训练。

具体功能如下:

  1. 读取人脸数据:从指定路径中读取人脸图片,并将其存储在imgs列表中,同时将对应的标签存储在labs列表中。
  2. 随机划分测试集与训练集:将读取到的人脸数据随机划分为训练集和测试集。
  3. 归一化:将训练集和测试集的图片数据进行归一化处理。
  4. 定义神经网络层:定义了一个包含八层的卷积神经网络模型,用于特征提取和分类。
  5. 定义训练函数:定义了训练过程,包括损失函数、优化器和准确率的计算。
  6. 进行训练:使用训练函数进行模型训练,训练过程中会输出损失和准确率。

7.系统整体结构

整体功能和构架概述:
该工程主要是一个人脸识别项目,包含了多个程序文件,用于实现不同的功能。其中,config.py用于配置参数和路径,deep_face.py用于人脸识别,demo.py用于演示人脸识别结果,faces_my.py用于采集自己的人脸数据集,faces_other.py用于采集其他人脸数据集,faces_train.py用于训练人脸分类模型,f_Face_info.py包含了一些人脸处理的函数,ui.py是一个用户界面文件,age_detection\f_my_age.py用于预测年龄,my_face_recognition\f_face_recognition.py用于人脸识别,my_face_recognition\f_main.py是主程序文件,my_face_recognition\f_storage.py用于存储人脸数据。

下面是每个文件的功能整理:

文件名 功能
config.py 配置参数和路径
deep_face.py 人脸识别
demo.py 演示人脸识别结果
faces_other.py 人脸数据集
faces_train.py 训练人脸分类模型
f_Face_info.py 包含人脸处理的函数
ui.py 用户界面文件
my_face_recognition\f_face_recognition.py 人脸识别
my_face_recognition\f_main.py 主程序文件
face_db 存储人脸数据

8.系统整合

下图完整源码&环境部署视频教程&数据集&自定义UI界面

1.jpg

参考博客《基于卷积神经网络人脸识别系统(部署教程&源码)》

9.参考文献


[1]程俊华,曾国辉,鲁敦科,等.基于Dropout的改进卷积神经网络模型平均方法[J].计算机应用.2019,(6).DOI:10.11772/j.issn.1001-9081.2018122501.

[2]景晨凯,宋涛,庄雷,等.基于深度卷积神经网络的人脸识别技术综述[J].计算机应用与软件.2018,(1).DOI:10.3969/j.issn.1000-386x.2018.01.039.

[3]卢官明,何嘉利,闫静杰,等.一种用于人脸表情识别的卷积神经网络[J].南京邮电大学学报(自然科学版).2016,(1).DOI:10.14132/j.cnki.1673-5439.2016.01.003.

[4]张洁玉,赵鸿萍,陈曙.自适应阈值及加权局部二值模式的人脸识别[J].电子与信息学报.2014,(6).DOI:10.3724/SP.J.1146.2013.01218.

[5]刘中华,史恒亮,张兰萍,等.基于多尺度局部二值模式的人脸识别[J].计算机科学.2009,(11).DOI:10.3969/j.issn.1002-137X.2009.11.074.

[6]刘碧靓.基于深度学习的车辆识别系统的设计与实现[J].苏州大学.2017.

[7]杨子文.基于深度卷积神经网络的人脸识别研究[J].广西师范大学.2017.

[8]万士宁.基于卷积神经网络的人脸识别研究与实现[J].电子科技大学.2016.

[9]吴斯.基于多尺度池化的卷积神经网络人脸识别方法研究[J].浙江大学.2016.

[10]叶浪.基于卷积神经网络的人脸识别研究[J].东南大学.2015.


如果您需要更详细的【源码和环境部署教程】,除了通过【系统整合】小节的链接获取之外,还可以通过邮箱以下途径获取:

1.请先在GitHub上为该项目点赞(Star),编辑一封邮件,附上点赞的截图、项目的中文描述概述(About)以及您的用途需求,发送到我们的邮箱

sharecode@yeah.net

2.我们收到邮件后会定期根据邮件的接收顺序将【完整源码和环境部署教程】发送到您的邮箱。

【免责声明】本文来源于用户投稿,如果侵犯任何第三方的合法权益,可通过邮箱联系删除。