基于python实现resnet_使⽤dlib中的深度残差⽹络(ResNet)
实现实时⼈脸识别
opencv中提供的基于haar特征级联进⾏⼈脸检测的⽅法效果⾮常不好,本⽂使⽤dlib中提供的⼈脸检测⽅法(使⽤HOG特征或卷积神经⽹⽅法),并使⽤提供的深度残差⽹络(ResNet)实现实时⼈脸识别,不过本⽂的⽬的不是构建深度残差⽹络,⽽是利⽤已经训练好的模型进⾏实时⼈脸识别,实时性要求⼀秒钟达到10帧以上的速率,并且保证不错的精度。opencv和dlib都是⾮常好⽤的计算机视觉库,特别是dlib,前⾯⽂章提到了其内部封装了⼀些⽐较新的深度学习⽅法,使⽤这些算法可以实现很多应⽤,⽐如⼈脸检测、车辆检测、⽬标追踪、语义分割等等。由于这两个库相应的都包含了C++和Python的版本,⽽Python的配置和相对使⽤起来更加简单,因此这篇⽂章主要通过Python 来实现。
先上测试的识别效果,第⼀张识别吴恩达和Bengio,后者我没有打标签所以识别的是“other”;另外⼀张gif 是识别梁朝伟、刘德华和⼀个⼥主持的过程,本地库中没有存储⼥主持的图⽚。
因为博客园不⽅便上传本地视频,所以⽤的gif显⽰效果图,源视频要⽐gif清楚,640X480像素⼤⼩,总的来说效果识别的效果还不错。⼀、准备
(2)需要⼀个和PC连接的摄像头;在本⽂中使⽤的是串⼝的摄像头,笔记本电脑集成的摄像头就是串⼝的,
opencv中提供了直接获取串⼝摄像头的接⼝,⾮常⽅便使⽤;如果是⽹⼝的摄像头那么就要看摄像头提供⽅,⽐如⼤华、海康他们的摄像头可能会提供官⽅的SDK,如果有接⼝那是最好;或者,如果摄像头⽀持RTSP协议,opencv也可以通过RTSP协议获取摄像头的数据;否则可能就要写⼀套socket通信来实现数据传输,这个不在本⽂范围之内,默认使⽤的是串⼝的摄像头。
⼆、策略
⼈脸识别分为⼈脸检测和识别两个阶段,⼈脸检测会到⼈脸区域的矩形窗⼝,识别则通过ResNet返回⼈脸特征向量,并进⾏匹配。
(1)⼈脸检测阶段。⼈脸检测算法需要⽤⼤⼩位置不同的窗⼝在图像中进⾏滑动,然后判断窗⼝中是否存在⼈脸。在深度学习之前的主流⽅法是特征提取+集成学习分类器,⽐如以前⽕热的haar特征+adaboost级联分类器,opencv中实现的⼈脸检测⽅法就采⽤了这种,不过实验结果来看,这种检测⽅法效果很不好,经常误检测⼈脸,或者检测不到真实的⼈脸;dlib中使⽤的是HOG(histogram of oriented gradient)+ 回归树的⽅法,使⽤dlib训练好的模型进⾏检测效果要好很多。dlib也使⽤了卷积神经⽹络来进⾏⼈脸检测,效果好于HOG的集成学习⽅法,不过需要使⽤GPU加速,不然程序会卡爆了,⼀张图⽚可能⼏秒甚⾄⼏⼗秒。
(2)识别阶段。识别也就是我们常说的“分类”,摄像头采集到这个⼈脸时,让机器判断是张三还是其他
⼈。分类分为两个部分:
特征向量抽取。本⽂⽤到的是dlib中已经训练好的ResNet模型的接⼝,此接⼝会返回⼀个128维的⼈脸特征向量。
距离匹配。在获取特征向量之后可以使⽤欧式距离和本地的⼈脸特征向量进⾏匹配,使⽤最近邻分类器返回样本的标签。
根据以上,识别的⼤致过程如下:
图1 ⼈脸识别分类过程
对于图1中的获取⼈脸特征向量,其过程如下:
图2 获取⼈脸特征向量过程
⽤简单的话总结,整个过程分为两个阶段,本地存储已标记⼈脸数据;识别阶段把从摄像头读取的⼈脸和本地进⾏匹配,得到分类结果。
三、程序实现
(1)构建本地⼈脸特征向量库,并且打标签。
⾸先加载需要的python库:
importdlibimportnumpy as npimportcv2importosimport json
然后加载模型参数:
detector = dlibn_face_detection_model_v1('mmod_human_face_detector.dat')
sp= dlib.shape_predictor('shape_predictor_68_face_landmarks.dat')
facerec= dlib.face_recognition_model_v1('dlib_face_recognition_resnet_model_v1.dat')
最后,对某个⽬录中的所有图⽚进⾏处理,处理的⽅式是⼀张⼀张地读取某个⽬录中的图⽚,每读取⼀张就检测⼈脸,如果存在⼈脸就使⽤ResNet的接⼝获取⼈脸特性向量,保存到事先准备好的矩阵中,并且按照⽂件名存取标签,完了之后把所有的⼈脸特征向量和标签都存到本地的⽂本⽂件中。注意这⾥给图⽚打标签的⽅式,我把每张图⽚命名为标签名+下划线+序号+点号+后缀名的形式,标签名是⼿动命名的标记名称,序号⽤以区分同⼀类中的第⼏张。以下是demo中存放的部分图⽚:
也有很多其他的⽅法打标签,这⾥不多举例。
imagePath = 'LocalImage/' #图像的⽬录
data = np.zeros((1,128)) #定义⼀个128维的空向量data
label = [] #定义空的list存放⼈脸的标签
for file in os.listdir(imagePath): #开始⼀张⼀张索引⽬录中的图像
if '.jpg' in file or '.png' infile:
fileName=file
labelName= file.split('_')[0] #获取标签名
print('current image:', file)print('current label:', labelName)
img= cv2.imread(imagePath + file) #使⽤opencv读取图像数据
if img.shape[0]*img.shape[1] > 500000: #如果图太⼤的话需要压缩,这⾥像素的阈值可以⾃⼰设置
img = size(img, (0,0), fx=0.5, fy=0.5)
dets= detector(img, 1) #使⽤检测算⼦检测⼈脸,返回的是所有的检测到的⼈脸区域
for k, d inenumerate(dets):
left(),p(),d.rect.right(),d.rect.bottom())
shape= sp(img, rec) #获取landmark
face_descriptor = facerecpute_face_descriptor(img, shape) #使⽤resNet获取128维的⼈脸特征向量
faceArray = np.array(face_descriptor).reshape((1, 128)) #转换成numpy中的数据结构
data = np.concatenate((data, faceArray)) #拼接到事先准备好的data当中去
label.append(labelName) #保存标签
cv2.waitKey(2)
cv2.imshow('image', img)
data= data[1:, :] #因为data的第⼀⾏是空的128维向量,所以实际存储的时候从第⼆⾏开始
np.savetxt('', data, fmt='%f') #保存⼈脸特征向量合成的矩阵到本地
labelFile=open('','w')
json.dump(label, labelFile)#使⽤json保存list到本地
labelFile.close()
cv2.destroyAllWindows()#关闭所有的窗⼝
上⾯的代码中,会索引imagePath这个存放图像的⽬录;然后定义⼀个128维的空向量data,在后续获取每⼀张⼈脸特征向量的时候可以往这个向量后⾯追加,即data的每⼀⾏是⼀个样本的特征向量;然后定义⼀个list来存储标签。之后开始索引某个⽬录下所有的图⽚⽂件。注意我这⾥⽤的是opencv的接⼝读取图像,也可以使⽤其他的图像读取接⼝,⽐如dlib⾃带的或者PIL接⼝中的,都可以使⽤,不过重要的是接⼝⼀定要统⼀,因为每个接⼝读取图⽚转成矩阵的数值可能会有差异。然后使⽤前⾯定义的测算⼦开始检测⼈脸,返回的是dlib中的⼀个数据结构,这个数据结构存储了所有检测到的⼈脸区域信息,对每个检测到的⼈脸区域获取landmark,并且调⽤深度残差模型的接⼝获取128维的⼈脸特征向量,之后我们把这个⼈脸向量存储到data中去,这⾥使⽤numpy中提供的concatenate⽅法进⾏拼接,
python怎么读取dat文件同时把标签添加到label列表中去。最后,因为data事先定义的是⼀个128维的空向量,之后利⽤concatenate⽅法进⾏拼接得到,我们需要抛弃第⼀⾏;最后把得到的⼈脸特征和标签存储到本地⽂件。
这⾥使⽤的是CNN进⾏⼈脸检测,如果你没有GPU,或者你有GPU但没有进⾏GPU的配置,那么速度巨慢,此时你可以使⽤传统的HOG特征+级联分类的⽅法,不过效果没有CNN的好。这时代码的第6⾏中模型需要替换成:
detector = _frontal_face_detector()
其余的基本保持不变。
以上的代码可以直接运⾏,运⾏之后会检测所有的图像,类似于:
并且存取得到本地的⼈脸特征向量库和标签:
(2)实时读取摄像头进⾏⼈脸识别
在(1)中我们已经得到了本地的打过标签的⼈脸特征向量,这⼀部分是实现读取摄像头实时识别。⾸先加载需要的python库:
importdlibimportnumpy as npimportcv2import json
然后加载神经⽹络模型:
detector = dlibn_face_detection_model_v1('mmod_human_face_detector.dat')
sp= dlib.shape_predictor('shape_predictor_68_face_landmarks.dat')
facerec= dlib.face_recognition_model_v1('dlib_face_recognition_resnet_model_v1.dat')
threshold= 0.54
其中threshold是⼈脸识别的阈值,当测试图⽚和本地图⽚欧式距离最近的值⼤于这个值的时候,我们认为不属于本都图⽚的任何⼀个类别。然后定义最近邻分类器:
deffindNearestClassForImage(face_descriptor, faceLabel):
temp= face_descriptor -data
e= (temp,axis=1,keepdims=True)
min_distance=e.min()print('distance:', min_distance)if min_distance >threshold:return 'other'index=np.argmin(e)return faceLabel[index]
当距离值⼤于threshold的时候我们返回标签“other”,否则返回本地的标签,你可以根据实际情况来设置这个阈值。题外话,安全阈值很依赖于具体的场合,⽐如安检、银⾏⾥进⾏⼈脸验证、iPhone解锁,这些对安全要求很⾼的场合需要⽐较⼩的threshold来保证安全,在嫌犯追踪的时候,需要⽐较⼤的threshold以保证由嫌疑的⼈不会漏过。
然后是读取图像进⾏识别的函数:
defrecognition(img):
dets= detector(img, 1)for k, d inenumerate(dets):print("Detection {}: Left: {} Top: {} Right: {} Bottom: {}".format(
k, d.rect.left(), p(), d.rect.right(), d.rect.bottom()))
left(),p(),d.rect.right(),d.rect.bottom())print(rec.left(),p(),rec.right(),rec.bottom())
shape=sp(img, rec)
face_descriptor=facerecpute_face_descriptor(img, shape)
class_pre=findNearestClassForImage(face_descriptor, label)print(class_pre)
cv2.putText(img, class_pre , (rec.left(),p()), cv2.FONT_HERSHEY_SIMPLEX,0.7, (0,255,0), 2, cv2.LINE_AA)
cv2.imshow('image', img)
最后是实时读取摄像头图像,并且进⾏识别的过程:
labelFile=open('','r')
label= json.load(labelFile) #载⼊本地⼈脸库的标签
labelFile.close()
data= np.loadtxt('',dtype=float) #载⼊本地⼈脸特征向量
cap=cv2.VideoCapture(0)
fps= 10size= (640,480)
fourcc= cv2.VideoWriter_fourcc(*'XVID')
videoWriter= cv2.VideoWriter('video.MP4', fourcc, fps, size)while(1):
ret, ad()#frame = size(frame, (0,0), fx=0.5, fy=0.5)
recognition(frame)
videoWriter.write(frame)if cv2.waitKey(1) & 0xFF == ord('q'):lease()
cv2.destroyAllWindows()
在上⾯的代码中为了展⽰检测的效果,我⽤opencv的接⼝把图像保存到了视频当中。识别效果截图:
四、总结
利⽤已有的计算机视觉库可以实现很多好玩和有⽤的应⽤,本⽂只是粗略地展⽰了⼀个进⾏实时⼈脸
识别的demo,还有很多可以改善的点来提⾼精度和效率,⽐如⼈脸受⾓度、表情影响很⼤,或者需要处理速度要求更⾼的场景;同时图像类别规模很⼤的情况下如何保证效果,如何优化这些都是难点。另外dlib中的提供的这些模型都是已经训练好的,我们可以到官⽅demo下载,demo给出了在⼀些benchmark中的效果,也可以⾃⼰训练得到这些模型,当然前提是你需要有GPU,并且要求很⼤量的数据以及丰富的调参经验,这些也都是深度学习中的点~
(完)
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论