700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > AI人脸识别技术当今的发展

AI人脸识别技术当今的发展

时间:2021-05-10 12:12:52

相关推荐

AI人脸识别技术当今的发展

AI人脸识别技术当今的发展

人脸识别技术的发展背景

人脸识别技术在中国的发展起步于上世纪九十年代末,经历了技术引进-专业市场导入-技术完善-技术应用-各行业领域使用等五个阶段。其中,是深度学习应用于人脸识别的关键一年,该年FaceBook发表一篇名为“Deep Face系统:达到肉眼级别的人脸识别系统”(翻译名),之后Face++创始人印奇团队以及香港中文大学汤晓鸥团队均在深度学习结合人脸识别领域取得优异效果,两者在LFW数据集上识别准确度均超过了99%,而肉眼在该数据集上的识别准确度仅为97.52%,可以说深度学习技术让计算机人脸识别能力超越人类的识别程度。

目前,国内的人脸识别技术已经相对发展成熟,该技术越来越多的被推广到安防领域,延伸出考勤机、门禁机等多种产品,产品系列达20多种类型,可以全面覆盖煤矿、楼宇、银行、军队、社会福利保障、电子商务及安全防务等领域,人脸识别的全面应用时代已经到来。

算法介绍

人脸识别的核心任务为face detection,face verification 和 face identification。这里需要对这三个任务进行科普。Face detection, 对图像中的人脸进行检测,并将结果用矩形框框出来。

人脸校正Face alignment,对检测到的人脸进行姿态的校正,使其人脸尽可能的”正”,通过校正可以提高人脸识别的精度。校正的方法有2D校正、3D校正的方法,3D校正的方法可以使侧脸得到较好的识别。目前校正在处理过程中完全可以达到实时性的要求,具体可以阅读Face Alignment at 3000 FPS via Regressing Local Binary Features这篇文章(论文笔记)。在进行人脸校正的时候,会有检测特征点的位置这一步,这些特征点位置主要是诸如鼻子左侧,鼻孔下侧,瞳孔位置,上嘴唇下侧等等位置,知道了这些特征点的位置后,做一下位置驱动的变形,脸即可被校”正”了。下面两幅图像分别显示了原来的人脸和经过校正后了的人脸。

人脸校验Face verification,人脸校验是基于pair matching的方式,所以它得到的答案是“是”或者“不是”。在具体操作的时候,给定一张测试图片,然后挨个进行pair matching,matching上了则说明测试图像与该张匹配上的人脸为同一个人的人脸。一般在小型办公室人脸刷脸打卡系统中采用的(应该)是这种方法,具体操作方法大致是这样一个流程:离线逐个录入员工的人脸照片(一个员工录入的人脸一般不止一张),员工在刷脸打卡的时候相机捕获到图像后,通过前面所讲的先进行人脸检测,然后进行人脸校正,再进行人脸校验,一旦match结果为“是”,说明该名刷脸的人员是属于本办公室的,人脸校验到这一步就完成了。在离线录入员工人脸的时候,我们可以将人脸与人名对应,这样一旦在人脸校验成功后,就可以知道这个人是谁了。上面所说的这样一种系统优点是开发费用低廉,适合小型办公场所,缺点是在捕获时不能有遮挡,而且还要求人脸姿态比较正。下图给出了示意说明,不过那个“Am I SW?”应该改一下,改成“Am I the same to the seleted face image?”。

人脸识别Face identification或Face recognition,人脸识别正如下图所示的,它要回答的是“我是谁?”,相比于人脸校验采用的pair matching,它在识别阶段更多的是采用分类的手段。它实际上是对进行了前面两步即人脸检测、人脸校正后做的图像(人脸)分类。

根据上面所介绍的这4个概念,人脸识别包括下面三个模块:

上面进行细拆分包括下图所示的几个步骤:

对上面的概念清楚了后,我们再接着讲一下在人脸识别里面的人脸图像数据库。

人脸图像数据库人脸图像这个东西因为受到安全隐私等限制,所以一般大规模的人脸数据库比较难拿到,目前我知道到的公开的人脸图像库有LFW(Labelled Faces in the Wild)和YFW(Youtube Faces in the Wild)。下面再列举一些大规模的人脸图像数据库:

人脸识别按特征分类可以分成两种:一种是基于浅层特征的人脸识别,一种是基于深度学习的人脸识别方法。Deep Face Recognition这篇文章做了两件事:一是介绍了一种抓取网络上的图片并在有限的人力标注下得到一个大规模人脸图像的方法,二是测试了不同CNN网络结构下人脸校正以及度量学习对人脸识别的精度的影响。

浅层人脸识别方法

首先提取人脸图像的局部特征,比如SIFT、LBP、HOG等特征,然后通过某种pooling机制将它们aggregate成全局人脸描述子,如Fisher Vector(可以参阅A compact and discriminative face track descriptor和Fisher Vector Faces in the Wild这两篇文章)。

基于深度学习的人脸识别方法

通常使用CNN结构,比较典型的代码是DeepFace(Deep-Face:Closing the gap to human-level performance in the face verification),该方法使用一个深层的CNN网络结构,训练所使用的数据集数目为4百万,共包含4000个人的人脸。DeepFace在预处理的阶段使用了3D模型将人脸图像校准到典型姿态下。在当时DeepFace在LFW和在YFW人脸数据库上都取得了最好的结果。后来,文章的作者有对其工作进行了拓展(具体可以阅读Web-scale traing for face identification这篇文章),其训练图库比原来的图库大了两个量级,包括100万个人的脸(英文作identities),每个identity有50张图像,他们通过一种自举策略来选择identities进行网络的训练,并说明了可以通过控制全连接层的维数还提高网络的泛化能力。

DeepFace的工作后来被进一步拓展成了DeepId系列,具体可以阅读Y. Sun的4篇关于人脸识别的文章:

Deep learning face representation by joint identificationverification,在分类和验证(virification)的时候使用多任务学习。

Deep learning face representation from predicting 10,000 classes,将多个CNNs结构联合起来

Deeply learned face representations are sparse, selective, and robust,在全连接层前面使用不同的CNN结构。

Deepid3: Face recognition with very deep neural networks,使用更深的网络结构,大约用到了200个CNN结构,模型非常的复杂。

相比于DeepFace,DeepID没有使用3D的校准,而是使用了一种更简单的2D仿射校准,所用的训练图库是由CelebFaces和WDRef两个人脸图像库混合而成的。

在谷歌的Facenet中,谷歌的研究人员使用了前面介绍的人脸图像库中的Google人脸数据库上去训练CNN网络,他们使用的是”triplet-based”损失,通过最小化类内差异和最大化类间差异,并在训练阶段将该损失应用在多层(不仅仅是最后一层),在LFW和YTF上获得了最好的识别成绩。

人脸数据库搜集

获取候选人名。IMDB电影名人列表大约有500K个不同的人名,先从上面通过popularity排序获取到5k个人名,其中男女各一半。这些人名通过不断的筛选排除,最后得到了2622个人人名。

为每一个人名搜集图片。借助Google和Bing图片搜索引擎,分别按人名和人名 actor的两种方式进行查询,比如“Leonardo DiCaprio”和“Leonardo DiCaprio actor”,每次查询选前面500张,这样可以为每个人名(后面将其称为identity)获取到2000张图像。

用自动filter提高纯度。对于每一个基于Google查询的结果,将前50个样本作为正样本,其他identity查询的前50个结果作为负样本,用Fisher Vector描述子训练一个one-vs-rest线性分类器。用这个线性分类器对每一个identity的2000个下载结果进行排序,保留前1000个的结果。

删除近似样本:对每一幅图像计算其VLAD描述子,并对每一个identity的1000张图像进行聚类,经过这一步后,每个identity的图片数目为623个。文章在这一步说明操作的时候比较简略,比如聚类完后直接说”retaining a single element per cluster”,个人觉得没讲清楚,按照我的理解是应该是这么操作的:对每个identity的1000张图片聚类,聚类数目设置为623,聚完类后共623类,对每一类只保留跟那个类中心最近的那一幅图片,剔除掉该类的其他图片(这么做细想起来还是非常有道理的),这样每一个identity便得到了623张图片。

最终的人工过滤。这一步借助训练CNN网络来加速标注过程,具体操作按如下进行:选用AlexNet网络在这2622个identities上进行训练,然后用网络最后输出的softmax分数对每一个identity(此时的每一个identity包含有623张图片)进行降序排序,排序的依据是成为内点(按照我的理解这里的内点就是属于这个identity)的可能性,标注者按照排序的结果进行验证(文章里讲每一个identity的排序结果以200个块进行展示,如果近似纯度大于95%则说明这个块是好的,没怎么搞明白这个地方讲的),最后获取得了982803张较好的图片。

接下来获取人脸小数据集,lfw,生成人脸小图片:代码如下:

关键代码实现

借鉴别人的代码,首先,获取自己的图片信息,利用dlib切分成只有脸部信息的64*64的小图片。代码get_my_faces.py:

import cv2import dlibimport osimport sysimport randomoutput_dir = './my_faces'size = 64if not os.path.exists(output_dir):os.makedirs(output_dir)# 改变图片的亮度与对比度def relight(img, light=1, bias=0):w = img.shape[1]h = img.shape[0]#image = []for i in range(0,w):for j in range(0,h):for c in range(3):tmp = int(img[j,i,c]*light + bias)if tmp > 255:tmp = 255elif tmp < 0:tmp = 0img[j,i,c] = tmpreturn img#使用dlib自带的frontal_face_detector作为我们的特征提取器detector = dlib.get_frontal_face_detector()# 打开摄像头 参数为输入流,可以为摄像头或视频文件camera = cv2.VideoCapture(0)index = 6641while True:if (index <= 10000):print('Being processed picture %s' % index)# 从摄像头读取照片success, img = camera.read()# 转为灰度图片gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 使用detector进行人脸检测dets = detector(gray_img, 1)for i, d in enumerate(dets):x1 = d.top() if d.top() > 0 else 0y1 = d.bottom() if d.bottom() > 0 else 0x2 = d.left() if d.left() > 0 else 0y2 = d.right() if d.right() > 0 else 0face = img[x1:y1,x2:y2]# 调整图片的对比度与亮度, 对比度与亮度值都取随机数,这样能增加样本的多样性face = relight(face, random.uniform(0.5, 1.5), random.randint(-50, 50))face = cv2.resize(face, (size,size))cv2.imshow('image', face)cv2.imwrite(output_dir+'/'+str(index)+'.jpg', face)index += 1key = cv2.waitKey(1) & 0xffif key == 27:breakelse:print('Finished!')break# -*- codeing: utf-8 -*-import sysimport osimport cv2import dlibinput_dir = './input_img'output_dir = './other_faces'size = 64if not os.path.exists(output_dir):os.makedirs(output_dir)#使用dlib自带的frontal_face_detector作为我们的特征提取器detector = dlib.get_frontal_face_detector()index = 1for (path, dirnames, filenames) in os.walk(input_dir):for filename in filenames:if filename.endswith('.jpg'):print('Being processed picture %s' % index)img_path = path+'/'+filename# 从文件读取图片img = cv2.imread(img_path)# 转为灰度图片gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 使用detector进行人脸检测 dets为返回的结果dets = detector(gray_img, 1)#使用enumerate 函数遍历序列中的元素以及它们的下标#下标i即为人脸序号#left:人脸左边距离图片左边界的距离 ;right:人脸右边距离图片左边界的距离 #top:人脸上边距离图片上边界的距离 ;bottom:人脸下边距离图片上边界的距离for i, d in enumerate(dets):x1 = d.top() if d.top() > 0 else 0y1 = d.bottom() if d.bottom() > 0 else 0x2 = d.left() if d.left() > 0 else 0y2 = d.right() if d.right() > 0 else 0# img[y:y+h,x:x+w]face = img[x1:y1,x2:y2]# 调整图片的尺寸face = cv2.resize(face, (size,size))cv2.imshow('image',face)# 保存图片cv2.imwrite(output_dir+'/'+str(index)+'.jpg', face)index += 1key = cv2.waitKey(30) & 0xffif key == 27:sys.exit(0)

最后,进行训练,其实我看了源码,实则是一个类似于二分类器的东西,代码如下:

pythonimport tensorflow as tfimport cv2import numpy as npimport osimport randomimport sysfrom sklearn.model_selection import train_test_splitmy_faces_path = './my_faces'other_faces_path = './other_faces'size = 64imgs = []labs = []def getPaddingSize(img):h, w, _ = img.shapetop, bottom, left, right = (0,0,0,0)longest = max(h, w)if w < longest:tmp = longest - w# //表示整除符号left = tmp // 2right = tmp - leftelif h < longest:tmp = longest - htop = tmp // 2bottom = tmp - topelse:passreturn top, bottom, left, rightdef readData(path , h=size, w=size):for filename in os.listdir(path):if filename.endswith('.jpg'):filename = path + '/' + filenameimg = cv2.imread(filename)top,bottom,left,right = getPaddingSize(img)# 将图片放大, 扩充图片边缘部分img = cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT, value=[0,0,0])img = cv2.resize(img, (h, w))#print (labs)imgs.append(img)labs.append(path)readData(my_faces_path)readData(other_faces_path)# 将图片数据与标签转换成数组imgs = np.array(imgs)labs = np.array([[0,1] if lab == my_faces_path else [1,0] for lab in labs])# 随机划分测试集与训练集train_x,test_x,train_y,test_y = train_test_split(imgs, labs, test_size=0.05, random_state=random.randint(0,100))# 参数:图片数据的总数,图片的高、宽、通道train_x = train_x.reshape(train_x.shape[0], size, size, 3)test_x = test_x.reshape(test_x.shape[0], size, size, 3)# 将数据转换成小于1的数train_x = train_x.astype('float32')/255.0test_x = test_x.astype('float32')/255.0#print (test_x)print('train size:%s, test size:%s' % (len(train_x), len(test_x)))# 图片块,每次取100张图片batch_size = 100num_batch = len(train_x) // batch_sizex = tf.placeholder(tf.float32, [None, size, size, 3])y_ = tf.placeholder(tf.float32, [None, 2])keep_prob_5 = tf.placeholder(tf.float32)keep_prob_75 = tf.placeholder(tf.float32)def weightVariable(shape):init = tf.random_normal(shape, stddev=0.01)return tf.Variable(init)def biasVariable(shape):init = tf.random_normal(shape)return tf.Variable(init)def conv2d(x, W):return tf.nn.conv2d(x, W, strides=[1,1,1,1], padding='SAME')def maxPool(x):return tf.nn.max_pool(x, ksize=[1,2,2,1], strides=[1,2,2,1], padding='SAME')def dropout(x, keep):return tf.nn.dropout(x, keep)def cnnLayer():# 第一层W1 = weightVariable([3,3,3,32]) # 卷积核大小(3,3), 输入通道(3), 输出通道(32)b1 = biasVariable([32])# 卷积conv1 = tf.nn.relu(conv2d(x, W1) + b1)# 池化pool1 = maxPool(conv1)# 减少过拟合,随机让某些权重不更新drop1 = dropout(pool1, keep_prob_5)# 第二层W2 = weightVariable([3,3,32,64])b2 = biasVariable([64])conv2 = tf.nn.relu(conv2d(drop1, W2) + b2)pool2 = maxPool(conv2)drop2 = dropout(pool2, keep_prob_5)# 第三层W3 = weightVariable([3,3,64,64])b3 = biasVariable([64])conv3 = tf.nn.relu(conv2d(drop2, W3) + b3)pool3 = maxPool(conv3)drop3 = dropout(pool3, keep_prob_5)# 全连接层Wf = weightVariable([8*8*64, 512])bf = biasVariable([512])drop3_flat = tf.reshape(drop3, [-1, 8*8*64])dense = tf.nn.relu(tf.matmul(drop3_flat, Wf) + bf)dropf = dropout(dense, keep_prob_75)# 输出层Wout = weightVariable([512,2])bout = biasVariable([2])#out = tf.matmul(dropf, Wout) + boutout = tf.add(tf.matmul(dropf, Wout), bout)return outdef cnnTrain():out = cnnLayer()cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=out, labels=y_))train_step = tf.train.AdamOptimizer(0.01).minimize(cross_entropy)# 比较标签是否相等,再求的所有数的平均值,tf.cast(强制转换类型)accuracy = tf.reduce_mean(tf.cast(tf.equal(tf.argmax(out, 1), tf.argmax(y_, 1)), tf.float32))# 将loss与accuracy保存以供tensorboard使用tf.summary.scalar('loss', cross_entropy)tf.summary.scalar('accuracy', accuracy)merged_summary_op = tf.summary.merge_all()# 数据保存器的初始化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):# 每次取128(batch_size)张图片for i in range(num_batch):batch_x = train_x[i*batch_size : (i+1)*batch_size]batch_y = train_y[i*batch_size : (i+1)*batch_size]# 开始训练数据,同时训练三个变量,返回三个数据_,loss,summary = sess.run([train_step, cross_entropy, merged_summary_op],feed_dict={x:batch_x,y_:batch_y, keep_prob_5:0.5,keep_prob_75:0.75})summary_writer.add_summary(summary, n*num_batch+i)# 打印损失print(n*num_batch+i, loss)if (n*num_batch+i) % 100 == 0:# 获取测试数据的准确率acc = accuracy.eval({x:test_x, y_:test_y, keep_prob_5:1.0, keep_prob_75:1.0})print(n*num_batch+i, acc)# 准确率大于0.98时保存并退出if acc > 0.98 and n > 2:saver.save(sess, './train_faces.model', global_step=n*num_batch+i)sys.exit(0)print('accuracy less 0.98, exited!')cnnTrain()

最后,可以打开摄像头检测是否识别成功,代码如下:

import tensorflow as tfimport cv2import dlibimport numpy as npimport osimport randomimport sysfrom sklearn.model_selection import train_test_splitmy_faces_path = './my_faces'other_faces_path = './other_faces'size = 64imgs = []labs = []def getPaddingSize(img):h, w, _ = img.shapetop, bottom, left, right = (0,0,0,0)longest = max(h, w)if w < longest:tmp = longest - w# //表示整除符号left = tmp // 2right = tmp - leftelif h < longest:tmp = longest - htop = tmp // 2bottom = tmp - topelse:passreturn top, bottom, left, rightdef readData(path , h=size, w=size):for filename in os.listdir(path):if filename.endswith('.jpg'):filename = path + '/' + filenameimg = cv2.imread(filename)top,bottom,left,right = getPaddingSize(img)# 将图片放大, 扩充图片边缘部分img = cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT, value=[0,0,0])img = cv2.resize(img, (h, w))imgs.append(img)labs.append(path)readData(my_faces_path)readData(other_faces_path)# 将图片数据与标签转换成数组imgs = np.array(imgs)labs = np.array([[0,1] if lab == my_faces_path else [1,0] for lab in labs])# 随机划分测试集与训练集train_x,test_x,train_y,test_y = train_test_split(imgs, labs, test_size=0.05, random_state=random.randint(0,100))# 参数:图片数据的总数,图片的高、宽、通道train_x = train_x.reshape(train_x.shape[0], size, size, 3)test_x = test_x.reshape(test_x.shape[0], size, size, 3)# 将数据转换成小于1的数train_x = train_x.astype('float32')/255.0test_x = test_x.astype('float32')/255.0print('train size:%s, test size:%s' % (len(train_x), len(test_x)))# 图片块,每次取128张图片batch_size = 128num_batch = len(train_x) // 128x = tf.placeholder(tf.float32, [None, size, size, 3])y_ = tf.placeholder(tf.float32, [None, 2])keep_prob_5 = tf.placeholder(tf.float32)keep_prob_75 = tf.placeholder(tf.float32)def weightVariable(shape):init = tf.random_normal(shape, stddev=0.01)return tf.Variable(init)def biasVariable(shape):init = tf.random_normal(shape)return tf.Variable(init)def conv2d(x, W):return tf.nn.conv2d(x, W, strides=[1,1,1,1], padding='SAME')def maxPool(x):return tf.nn.max_pool(x, ksize=[1,2,2,1], strides=[1,2,2,1], padding='SAME')def dropout(x, keep):return tf.nn.dropout(x, keep)def cnnLayer():# 第一层W1 = weightVariable([3,3,3,32]) # 卷积核大小(3,3), 输入通道(3), 输出通道(32)b1 = biasVariable([32])# 卷积conv1 = tf.nn.relu(conv2d(x, W1) + b1)# 池化pool1 = maxPool(conv1)# 减少过拟合,随机让某些权重不更新drop1 = dropout(pool1, keep_prob_5)# 第二层W2 = weightVariable([3,3,32,64])b2 = biasVariable([64])conv2 = tf.nn.relu(conv2d(drop1, W2) + b2)pool2 = maxPool(conv2)drop2 = dropout(pool2, keep_prob_5)# 第三层W3 = weightVariable([3,3,64,64])b3 = biasVariable([64])conv3 = tf.nn.relu(conv2d(drop2, W3) + b3)pool3 = maxPool(conv3)drop3 = dropout(pool3, keep_prob_5)# 全连接层Wf = weightVariable([8*16*32, 512])bf = biasVariable([512])drop3_flat = tf.reshape(drop3, [-1, 8*16*32])dense = tf.nn.relu(tf.matmul(drop3_flat, Wf) + bf)dropf = dropout(dense, keep_prob_75)# 输出层Wout = weightVariable([512,2])bout = biasVariable([2])out = tf.add(tf.matmul(dropf, Wout), bout)return outoutput = cnnLayer() predict = tf.argmax(output, 1) saver = tf.train.Saver() sess = tf.Session() saver.restore(sess, tf.train.latest_checkpoint('.')) def is_my_face(image): res = sess.run(predict, feed_dict={x: [image/255.0], keep_prob_5:1.0, keep_prob_75: 1.0}) if res[0] == 1: return True else: return False #使用dlib自带的frontal_face_detector作为我们的特征提取器detector = dlib.get_frontal_face_detector()cam = cv2.VideoCapture(0) while True: _, img = cam.read() gray_image = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)dets = detector(gray_image, 1)if not len(dets):#print('Can`t get face.')cv2.imshow('img', img)key = cv2.waitKey(30) & 0xff if key == 27:sys.exit(0)for i, d in enumerate(dets):x1 = d.top() if d.top() > 0 else 0y1 = d.bottom() if d.bottom() > 0 else 0x2 = d.left() if d.left() > 0 else 0y2 = d.right() if d.right() > 0 else 0face = img[x1:y1,x2:y2]# 调整图片的尺寸face = cv2.resize(face, (size,size))print('Is this my face? %s' % is_my_face(face))cv2.rectangle(img, (x2,x1),(y2,y1), (255,0,0),3)cv2.imshow('image',img)key = cv2.waitKey(30) & 0xffif key == 27:sys.exit(0)sess.close()

检测结果取决于自己的人脸图片数据集,获取自己图片的时候多方位的采集数据。

学习了这么多的前辈的文章,我懂得了想设计一种一统天下的算法是痴人说梦,不同的目标识别必须为其量身定做相应的算法。即使是同一种目标,有时在不同的状态下,针对同一目标,也需要设计特定的算法。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。