第一句子网 - 唯美句子、句子迷、好句子大全
第一句子网 > Python人脸识别 Python3.7+OpenCV+Dlib+罗技C920摄像头 实现离线实时摄像头画面人脸检测+识别

Python人脸识别 Python3.7+OpenCV+Dlib+罗技C920摄像头 实现离线实时摄像头画面人脸检测+识别

时间:2019-04-30 10:32:08

相关推荐

Python人脸识别    Python3.7+OpenCV+Dlib+罗技C920摄像头 实现离线实时摄像头画面人脸检测+识别

Python人脸识别 Python3.7+OpenCV+Dlib+罗技C920摄像头 实现离线实时摄像头画面人脸检测+识别

示例效果 文末付完整工程链接参考博客一、准备数据二、训练数据三、单张图片测试训练后的模型四、实时获取摄像头画面中的人脸并识别五、完整代码六、工程链接

示例效果 文末付完整工程链接

打码了

参考博客

基于python的dlib库的人脸识别 Legolas~

Dlib人脸检测的基本原理 普罗米修斯1024

本文中文乱码问题参考博客 天上飞下一毛雪

一、准备数据

需要事先下载的资料:

shape_predictor_68_face_landmarks.dat

dlib_face_recognition_resnet_model_v1.dat

SIMYOU.TTF

haarcascade_frontalface_default.xml

准备模型的训练数据

新建一个文件夹取名:train_images,事先准备每个人的照片,并做好标签备注,图片名即标签。如下图所示:

准备模型的测试数据

新建另一个文件夹取名:test_images,放一些train_images里同一个人的不同的照片,去掉标签,如下图:

二、训练数据

# -*- coding:utf-8 -*-import cv2import dlibimport numpy as npimport osimport globimport jsonimport time'''# 参数说明:# train_image_path 为 上文 train_images 文件夹路径# predictor_path 为 shape_predictor_68_face_landmarks.dat 文件所在路径# recognition_path 为 dlib_face_recognition_resnet_model_v1.dat文件所在路径# isNew 为 判断是训练全新的模型还是说我需要在原来的模型基础上新增数据 True 为训练全新模型# old_model_path 为 旧模型文件的路径 txt文件# new_model_path 为 训练完后新模型的保存路径 txt文件# class_name_path 为 每个人脸图片的标签保存路径 txt文件'''def train_face_jpg(train_image_path, predictor_path, recognition_path, isNew, old_model_path, new_model_path, class_name_path):global class_names # 人脸标签的保存列表detector = dlib.get_frontal_face_detector() # 获取图片中的人脸(dlib在这块的性能比opencv差点,计算的时候可以在前后用两个time.time()相减看一下dlib人脸检测耗费的时间,模型训练部分暂时就先用这个,实时画面检测改用opencv去实现)predictor = dlib.shape_predictor(predictor_path) # 获取人脸68个关键点face_rec = dlib.face_recognition_model_v1(recognition_path) # 人脸识别descriptors = [] # 保存训练后的人脸信息的列表,最终转化为数组形式保存到txt文件# 判断是整个重新训练新模型还是在旧模型增加训练数据if isNew: # 训练全新的模型descriptors = []class_names = []else: # 为旧模型增加新的训练数据,训练一次模型是非常耗时的,# 当人脸数据比较少还好,如果数据很多的话,每次添加人脸都要从头重新训练的话费时费力,# 所以我们可以在以前的模型基础上,更新模型数据# 例如调用方法:train_face_jpg('new_train_images', 'shape_predictor_68_face_landmarks.dat', 'dlib_face_recognition_resnet_model_v1.dat', False, 'result.txt', 'result.txt', 'class_names.txt')# 其中 new_train_images 为新添加的人脸图的文件夹路径,训练完后的数据保存到原来的result.txt和class_names.txt即可if os.path.isfile(old_model_path): # 判断旧模型文件是否存在descriptors = np.loadtxt(old_model_path, dtype=list) # descriptors = descriptors.tolist()if os.path.isfile(class_name_path): # 判断旧模型对应的标签文件是否存在class_names = get_class_names(class_name_path)# 读取train_images文件夹下的所有图片for path in glob.glob(os.path.join(train_image_path, "*.jpg")): # 可读取中文路径image = cv2.imdecode(np.fromfile(path, dtype=np.uint8), -1) detection_train = detector(image, 1)# 计算每个图片的人脸数据for i, det in enumerate(detection_train):face_mark_train = predictor(image, det)face_des_train = pute_face_descriptor(image, face_mark_train)# 将数据保存到列表中descriptors.append(np.array(face_des_train))# 将图片名作为人脸标签保存temp_name = path.split('\\')[-1].split('.')[0]class_names.append(temp_name)print(class_names)# 保存人脸标签到class_name_pathwith open(class_name_path, 'w+') as f:for i in class_names:f.write(json.dumps(i, ensure_ascii=False))if i == class_names[len(class_names)-1]:breakf.write("\n")# 将训练后的模型数据保存到txtnp.savetxt(new_model_path, descriptors, fmt="%s")# 返回 人脸标签列表return get_class_names(class_name_path)# 调用if __name__ == '__main__':train_face_jpg('train_images', 'shape_predictor_68_face_landmarks.dat', 'dlib_face_recognition_resnet_model_v1.dat', True, 'result.txt', 'result.txt', 'class_names.txt')

三、单张图片测试训练后的模型

模型训练完后,可以在工程路径下看到result.txt和class_names.txt,前者为模型的训练数据,后者为对应的标签文件

现在我们任取test_images文件夹中的一张照片来和训练数据做对比

# coding=utf-8import dlibimport cv2import numpy as npimport timefrom PIL import Image, ImageDraw, ImageFontclass_names = []detector = 0predictor = 0face_rec = 0face_des_array = 0descriptors = []face_casecade = 0# 初始化模型'''# 参数说明:# predictor_path 为 shape_predictor_68_face_landmarks.dat 文件所在路径# recognition_path 为 dlib_face_recognition_resnet_model_v1.dat 文件所在路径# descriptors_path 为 模型的训练数据 也就是 result.txt 文件的路径# face_casecade_path 为 haarcascade_frontalface_default.xml 文件所在路径'''def face_recognition_init_from_txt(predictor_path, recognition_path, descriptors_path, face_casecade_path):global detector, predictor, face_rec, descriptors, face_casecadedetector = dlib.get_frontal_face_detector()predictor = dlib.shape_predictor(predictor_path)face_rec = dlib.face_recognition_model_v1(recognition_path)descriptors = np.loadtxt(descriptors_path)face_casecade = cv2.CascadeClassifier(face_casecade_path)# 获取标签名数组'''# 参数说明:# class_name_path 为 标签文件的路径 即 class_names.txt 文件的路径'''def get_class_names(class_name_path):label_list = []if os.path.exists(class_name_path):f = open(class_name_path, 'r', encoding='gb18030', errors='ignore').read()label_list = f.replace('\"', '').split('\n')#print(label_list)return label_list# 单张图片对比# 根据路径识别人脸'''# 参数说明:# file_path 为 需要测试的图片路径# class_names 为 人脸标签的数组 可通过加载 get_class_names(class_name_path) 方法获取'''def face_recognition_from_path(file_path, class_names):global detector, predictor, face_rec, face_des_arraydist = []image = cv2.imread(file_path)detection_test = detector(image, 1) # 获取测试图片中人脸信息for i, det in enumerate(detection_test):face_mark_test = predictor(image, det)face_des_test = pute_face_descriptor(image, face_mark_test)face_des_array = np.array(face_des_test)for v in descriptors:distance = np.linalg.norm(v - face_des_array) # 测试图片的数据与模型中的人脸数据做对比,求范数dist.append(distance)# dist.append(np.sqrt(np.sum(np.square(face_des_array-v))))print(class_names)print(dist)# np.argsort获取列表中最小的数的下标test_result = np.argsort(dist)print(test_result)# 打印最小的的数,这个是和模型中所有训练数据对比后取一个最小数值print(dist[test_result[0]])# 数值越小,代表相似度越高,但是这个最小数值可能也很大,就是说测试的图片可能在模型中没有,即为录入,# 所以加个0.5的阈值判断,最小的数值小于0.45,才算匹配到,否侧视为人脸未录入,这个最小数值根据实际情况取调整if dist[test_result[0]] < 0.45:if class_names[test_result[0]] in class_names:print("识别结果:", class_names[test_result[0]])else:print('人脸信息未录入')else:print('人脸信息未录入')# 调用if __name__ == '__main__':class_names = get_class_names('class_names.txt')face_recognition_from_path('test_images/test0.jpg', class_names)

根据上图准备的测试数据 test0.jpg 为局座,对比后最小的数值为0.269,下标为2 ,在标签列表中,下表2的标签为局座

识别结果:

多试几个: test4.jpg 为 乌蝇哥

face_recognition_from_path('test_images/test4.jpg', class_names)

test1.jpg 为 断水流大师兄 ,我们的模型里面是没有训练大师兄的数据的,所以即使返回了下标1,但是最小数值0.4895是大于0.45的,所以判断为未录入。

face_recognition_from_path('test_images/test1.jpg', class_names)

那我们来更新一下训练数据 ,新建一个文件夹取名 new_train_images,然后将断水流大师兄的照片放进去 如下图:

然后只需再调用一下train_face_jpg() ,修改一下参数设置,参数说明如下:

# 其中 new_train_images 为新添加的人脸图的文件夹路径,训练完后的数据保存到原来的result.txt和class_names.txt即可# False 为 不是全新的模型,而是更新旧模型train_face_jpg('new_train_images', 'shape_predictor_68_face_landmarks.dat', 'dlib_face_recognition_resnet_model_v1.dat', False, 'result.txt', 'result.txt', 'class_names.txt')

再次识别:

四、实时获取摄像头画面中的人脸并识别

dlib在人脸检测方面相比opencv更耗时,但是在识别方面更加专业,所以此处采用opecv去获取摄像头画面中人脸位置信息,然后再用dlib去做对比识别

# 首先将上文根据图片路径测试的方法改为根据Mat来识别# 根据Mat识别人脸def face_recognition_from_Mat(face_Mat, class_names):global detector, predictor, face_des_arraydist = []name = ''image = face_Matdetection_test = detector(image, 1)for i, det in enumerate(detection_test):face_mark_test = predictor(image, det)face_des_test = pute_face_descriptor(image, face_mark_test)face_des_array = np.array(face_des_test)for v in descriptors:distance = np.linalg.norm(v - face_des_array)dist.append(distance)# dist.append(np.sqrt(np.sum(np.square(face_des_array-v))))test_result = np.argsort(dist)if dist[test_result[0]] < 0.45:if class_names[test_result[0]] in class_names:name = class_names[test_result[0]]print("识别结果是:", name)else:name = '未录入'else:name = '未录入'print('人脸信息未录入')return name# 判断画面中是否存在人脸,存在再识别def get_face(frame, gray, train_images_names):global face_casecade # face_casecade 为上文初始化模型的时候的 face_casecade face = face_casecade.detectMultiScale(gray, 1.1, 5) # 利用opencv检测画面中是否存在人脸face_img = []for x, y, w, h in face:cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 0, 255), 2)face_img = gray[y:y + h, x:w + x]face_img = cv2.cvtColor(face_img, cv2.COLOR_GRAY2BGR)name = face_recognition_from_Mat(img, train_images_names) # 人脸识别并返回识别到的人名frame = change_cv2_draw(frame, name, (x, y - 50), 50, (255, 0, 0)) # 显示中文人名return frame#由于直接用opencv显示中文会乱码,所以先将图片格式转化为PIL库的格式,用PIL的方法写入中文,然后在转化为CV的格式'''# 参数说明:# image 为 输入的图像# strs 为 需要显示的中文# local 为 中文显示的坐标位置# sizes 为 文字大小# colour 为 颜色 RBG 空间 opencv则为BGR'''def change_cv2_draw(image,strs,local,sizes,colour):cv2img = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)pilimg = Image.fromarray(cv2img)draw = ImageDraw.Draw(pilimg)font = ImageFont.truetype("SIMYOU.TTF",sizes, encoding="utf-8") #SIMYOU.TTF为字体文件draw.text(local, strs, colour, font=font)image = cv2.cvtColor(np.array(pilimg), cv2.COLOR_RGB2BGR)return imagecap = cv2.VideoCapture(0) # while True:ret, frame = cap.read()gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)frame = get_face(frame, gray, class_names)cv2.imshow('frame', frame)cv2.waitKey(10)

到此结束

dlib库的人脸识别其实还是挺耗时的,一秒钟,大概能运算3次左右吧,如果觉得性能不够,可以自行尝试有没有什么方式可以优化一下性能

五、完整代码

train_face_data.py

# -*- coding:utf-8 -*-import dlibimport cv2import numpy as npimport osimport globimport jsonimport timeclass_names = []def get_class_names(class_name_path):label_list = []if os.path.exists(class_name_path):f = open(class_name_path, 'r', encoding='gb18030', errors='ignore').read()label_list = f.replace('\"', '').split('\n')#print(label_list)return label_listdef train_face_jpg(train_image_path, predictor_path, recognition_path, isNew, old_model_path, new_model_path, class_name_path):global class_namesdetector = dlib.get_frontal_face_detector()predictor = dlib.shape_predictor(predictor_path)face_rec = dlib.face_recognition_model_v1(recognition_path)descriptors = []# 判断是整个重新训练新模型还是在旧模型增加训练数据if isNew:descriptors = []class_names = []else:if os.path.isfile(old_model_path):descriptors = np.loadtxt(old_model_path, dtype=list)descriptors = descriptors.tolist()if os.path.isfile(class_name_path):class_names = get_class_names(class_name_path)for path in glob.glob(os.path.join(train_image_path, "*.jpg")):image = cv2.imdecode(np.fromfile(path, dtype=np.uint8), -1)detection_train = detector(image, 1)for i, det in enumerate(detection_train):face_mark_train = predictor(image, det)face_des_train = pute_face_descriptor(image, face_mark_train)descriptors.append(np.array(face_des_train))temp_name = path.split('\\')[-1].split('.')[0]class_names.append(temp_name)print(class_names)with open(class_name_path, 'w+') as f:for i in class_names:f.write(json.dumps(i, ensure_ascii=False))if i == class_names[len(class_names)-1]:breakf.write("\n")np.savetxt(new_model_path, descriptors, fmt="%s")return get_class_names(class_name_path)

face_recog.py

# 根据现有训练数据进行人脸识别类# coding=utf-8import dlibimport cv2import numpy as npimport timefrom PIL import Image, ImageDraw, ImageFontdetector = 0predictor = 0face_rec = 0face_des_array = 0descriptors = []face_casecade = 0# 初始化模型def face_recognition_init_from_txt(predictor_path, recognition_path, descriptors_path, face_casecade_path):global detector, predictor, face_rec, descriptors, face_casecadedetector = dlib.get_frontal_face_detector()predictor = dlib.shape_predictor(predictor_path)face_rec = dlib.face_recognition_model_v1(recognition_path)descriptors = np.loadtxt(descriptors_path)face_casecade = cv2.CascadeClassifier(face_casecade_path)#根据路径识别人脸def face_recognition_from_path(file_path, class_names):global detector, predictor, face_rec, face_des_arraydist = []image = cv2.imread(file_path)detection_test = detector(image, 1)for i, det in enumerate(detection_test):face_mark_test = predictor(image, det)face_des_test = pute_face_descriptor(image, face_mark_test)face_des_array = np.array(face_des_test)for v in descriptors:distance = np.linalg.norm(v - face_des_array)dist.append(distance)# dist.append(np.sqrt(np.sum(np.square(face_des_array-v))))print(class_names)print(dist)test_result = np.argsort(dist)print(test_result[0])print(dist[test_result[0]])if dist[test_result[0]] < 0.45:if class_names[test_result[0]] in class_names:print("人脸识别的结果是:", class_names[test_result[0]])else:passelse:print('人脸信息未录入')#根据Mat识别人脸def face_recognition_from_Mat(face_Mat, class_names):global detector, predictor, face_des_arraydist = []name = ''image = face_Matdetection_test = detector(image, 1)for i, det in enumerate(detection_test):face_mark_test = predictor(image, det)face_des_test = pute_face_descriptor(image, face_mark_test)face_des_array = np.array(face_des_test)for v in descriptors:distance = np.linalg.norm(v - face_des_array)dist.append(distance)# dist.append(np.sqrt(np.sum(np.square(face_des_array-v))))test_result = np.argsort(dist)if dist[test_result[0]] < 0.45:if class_names[test_result[0]] in class_names:name = class_names[test_result[0]]print("识别结果是:", name)else:name = '未录入'else:name = '未录入'print('人脸信息未录入')return name# 判断画面中是否存在人脸def get_face(frame, gray, train_images_names):global face_casecadeface = face_casecade.detectMultiScale(gray, 1.1, 5)face_img = []for x, y, w, h in face:cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 0, 255), 2)face_img = gray[y:y + h, x:w + x]face_img = cv2.cvtColor(face_img, cv2.COLOR_GRAY2BGR)for img in face_img:name = face_recognition_from_Mat(img, train_images_names)frame = change_cv2_draw(frame, name, (x, y - 50), 50, (255, 0, 0))return frame#由于直接用opencv显示中文会乱码,所以先将图片格式转化为PIL库的格式,用PIL的方法写入中文,然后在转化为CV的格式def change_cv2_draw(image,strs,local,sizes,colour):cv2img = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)pilimg = Image.fromarray(cv2img)draw = ImageDraw.Draw(pilimg)font = ImageFont.truetype("SIMYOU.TTF",sizes, encoding="utf-8") #SIMYOU.TTF为字体文件draw.text(local, strs, colour, font=font)image = cv2.cvtColor(np.array(pilimg), cv2.COLOR_RGB2BGR)return image

main.py

import face_recog as frimport train_face_data as tfdimport jsonimport cv2import time# 在原有的模型基础上添加数据# tfd.train_face_jpg('new_train_images', 'shape_predictor_68_face_landmarks.dat', 'dlib_face_recognition_resnet_model_v1.dat', False, 'result.txt', 'result.txt', 'class_names.txt')# 训练全新的模型# class_names = tfd.train_face_jpg('train_images', 'shape_predictor_68_face_landmarks.dat', 'dlib_face_recognition_resnet_model_v1.dat', True, 'result.txt', 'result.txt', 'class_names.txt')#初始化模型fr.face_recognition_init_from_txt('shape_predictor_68_face_landmarks.dat', 'dlib_face_recognition_resnet_model_v1.dat', 'result.txt', 'haarcascade_frontalface_default.xml')class_names = tfd.get_class_names('class_names.txt')# 单张图片测试fr.face_recognition_from_path('test_images/test1.jpg', class_names)# 实时摄像头画面识别cap = cv2.VideoCapture(0)while True:ret, frame = cap.read()gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)frame = fr.get_face(frame, gray, class_names)cv2.imshow('frame', frame)cv2.waitKey(10)

六、工程链接

python离线人脸检测识别

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