Python人脸检测及识别
开发环境:
- Ubuntu16.04
- Python3.6 / Tensorflow1.8
项目目标:
- 实时识别检测人脸,并识别人物;
项目思路:
- 使用mtcnn模型检测人脸,并提取人脸图像成对应数据集;
- 使用facenet模型对数据集中每张人脸进行特征提取,构建每张图片对应128d维数据特征;
- 建立人脸特征库;
- 对待识别人脸,进行1、 2步骤,将提取的特征与人脸特征库进行相似度计算,找到相似性较高的对应人脸;
具体实施:
-
opencv人像采集:
使用opencv进行人像采集,其中使用ssd人脸检测器(快且准),详细代码如下get_face.py
:import os import cv2 import numpy as np from cv2_face_detector import FaceDetector # OpenCv 调用摄像头 use camera cap = cv2.VideoCapture(0) cnt_ss = 0 # 存储人脸的文件夹 current_face_dir = "" # 保存 faces images 的路径 path_photos_from_camera = "./faces_from_camera/" # 新建保存人脸图像文件 def pre_work_mkdir(): if os.path.isdir(path_photos_from_camera): pass else: os.mkdir(path_photos_from_camera) pre_work_mkdir() # 如果有之前录入的人脸 # 在之前 person_x 的序号按照 person_x+1 开始录入 if os.listdir("./faces_from_camera/"): # 获取已录入的最后一个人脸序号 / get the num of latest person person_list = os.listdir("./faces_from_camera/") person_num_list = [] for person in person_list: person_num_list.append(int(person.split('_')[-1])) person_cnt = max(person_num_list) # 如果第一次存储或者没有之前录入的人脸, 按照 person_1 开始录入 else: person_cnt = 0 # 之后用来控制是否保存图像的 flag save_flag = 1 # 之后用来检查是否先按 'n' 再按 's' press_n_flag = 0 # 使用ssd 人脸检测器 faceDetector = FaceDetector('ssd', 0.5) # 字体类型 font = cv2.FONT_HERSHEY_COMPLEX while cap.isOpened(): flag, img_rd = cap.read() kk = cv2.waitKey(1) frame = img_rd.copy() faces = faceDetector.detect(frame) # 固定截取窗口 (x,y,w,h) = (150,100,250,250) cv2.rectangle(frame, (x, y),(x+w, y+h), (0, 0, 255) , 2) # press 'n' to create the folders for saving faces if kk == ord('n'): person_cnt += 1 current_face_dir = path_photos_from_camera + "person_" + str(person_cnt) os.makedirs(current_face_dir) print('\n') print("新建的人脸文件夹 / Create folders: ", current_face_dir) cnt_ss = 0 # clear the cnt of faces press_n_flag = 1 # have pressed 'n' # 检测到人脸 if len(faces) != 0: print(len(faces)) for rect in faces: (x, y, w, h) = rect cv2.rectangle(frame, (x, y),(x+w, y+h), (0, 255, 0) , 2) if save_flag: # press 's' to save faces into local images if kk == ord('s'): # check if you have pressed 'n' if press_n_flag: cnt_ss += 1 # 保存固定窗口截图 im_blank = img_rd[100:350,150:400,:] cv2.imwrite(current_face_dir + '/' +str("%03d" % cnt_ss) + ".jpg", im_blank) print("写入本地 / Save into:", str(current_face_dir)+ '/' + str("%03d" % cnt_ss) + ".jpg") else: print("Please press 'N' before 'S'") # # 添加说明 / add some statements cv2.putText(frame, "Face Register", (20, 40), font, 1, (0, 0, 0), 1, cv2.LINE_AA) cv2.putText(frame, "N: New face folder", (20, 350), font, 0.8, (0, 0, 0), 1, cv2.LINE_AA) cv2.putText(frame, "S: Save current face", (20, 400), font, 0.8, (0, 0, 0), 1, cv2.LINE_AA) cv2.putText(frame, "Q: Quit", (20, 450), font, 0.8, (0, 0, 0), 1, cv2.LINE_AA) # show the numbers of faces detected cv2.putText(img_rd, "Faces: " + str(len(faces)), (20, 100), font, 0.8, (0, 255, 0), 1, cv2.LINE_AA) # press 'q' to exit if kk == ord('q'): break # 如果需要摄像头窗口大小可调 cv2.namedWindow("camera", 0) cv2.imshow("camera", frame) # 释放摄像头 / release camera cap.release() cv2.destroyAllWindows()
人脸采集过程截图:
-
facenet提取人脸特征:
-
mtcnn检测人脸,剪裁有效人脸区域
-
facene提取人脸特征
详细代码如下face_feature.py
import cv2 import csv from os.path import join as pjoin import skimage import tensorflow as tf import numpy as np import os import facenet import align.detect_face minsize = 20 # minimum size of face threshold = [ 0.6, 0.7, 0.7 ] # three steps's threshold factor = 0.709 # scale factor # 创建mtcnn网络,并加载参数 print('Creating networks and loading parameters') with tf.Graph().as_default(): gpu_options = tf.GPUOptions(per_process_gpu_memory_fraction=0.5) sess = tf.Session(config=tf.ConfigProto(gpu_options=gpu_options, log_device_placement=False)) with sess.as_default(): pnet, rnet, onet = align.detect_face.create_mtcnn(sess, None) def load_and_align_data(image, image_size, margin, gpu_memory_fraction): # 读取图片 img = image # 获取图片的shape img_size = np.asarray(img.shape)[0:2] # 返回边界框数组 (参数分别是输入图片 脸部最小尺寸 三个网络 阈值 factor不清楚) bounding_boxes, _ = align.detect_face.detect_face(img, minsize, pnet, rnet, onet, threshold, factor) # 如果检测出图片中不存在人脸 则直接返回,return 0(表示不存在人脸,跳过此图) if len(bounding_boxes) < 1: return 0,0,0 else: crop=[] det=bounding_boxes det[:,0]=np.maximum(det[:,0], 0) det[:,1]=np.maximum(det[:,1], 0) det[:,2]=np.minimum(det[:,2], img_size[1]) det[:,3]=np.minimum(det[:,3], img_size[0]) det=det.astype(int) for i in range(len(bounding_boxes)): temp_crop=img[det[i,1]:det[i,3],det[i,0]:det[i,2],:] aligned=skimage.transform.resize(temp_crop, (image_size, image_size)) prewhitened = facenet.prewhiten(aligned) crop.append(prewhitened) crop_image=np.stack(crop) return det,crop_image,1 def to_rgb(img): w, h = img.shape ret = np.empty((w, h, 3), dtype=np.uint8) ret[:, :, 0] = ret[:, :, 1] = ret[:, :, 2] = img return ret def load_data(data_dir): # data为字典类型 key对应人物分类 value为读取的一个人的所有图片 类型为ndarray data = {} pics_ctr = 0 for guy in os.listdir(data_dir): person_dir = pjoin(data_dir, guy) curr_pics = [read_img(person_dir, f) for f in os.listdir(person_dir)] # 存储每一类人的文件夹内所有图片 data[guy] = curr_pics return data def read_img(person_dir,f): img=cv2.imread(pjoin(person_dir, f)) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 判断数组维度 if gray.ndim == 2: img = to_rgb(gray) return img # 模型位置 model_dir='./models/facenet/' with tf.Graph().as_default(): with tf.Session() as sess: # 加载facenet模型 facenet.load_model(model_dir) # 返回给定名称的tensor images_placeholder = tf.get_default_graph().get_tensor_by_name("input:0") embeddings = tf.get_default_graph().get_tensor_by_name("embeddings:0") phase_train_placeholder = tf.get_default_graph().get_tensor_by_name("phase_train:0") # 从训练数据文件夹中加载图片并剪裁,最后embding,data为dict data=load_data('./train_data/') # keys列表存储图片文件夹类别(几个人) keys=[] for key in data: keys.append(key) print('folder:{},image numbers:{}'.format(key,len(data[key]))) # 使用mtcnn模型获取每张图中face的数量以及位置,并将得到的embedding数据存储 for n in range(len(keys)): for x in data[keys[n]]: _,images_me,i = load_and_align_data(x, 160, 44, 1.0) if i: feed_dict = { images_placeholder: images_me, phase_train_placeholder:False } emb = sess.run(embeddings, feed_dict=feed_dict) for xx in range(len(emb)): emb=list(emb[xx,:]) emb.append(keys[n]) with open('face_feature.csv', "a+", newline="") as csvfile: writer = csv.writer(csvfile) writer.writerow(emb)
-
人脸特征库建立
上述步骤生成文件face_feature.csv
即为已经采集的人脸特征库; -
效果验证
在数据集处理过程中,已经将数据集分为训练集和测试集,比例约为8:2,经过验证比对,平均准确率达到百分之95以上,具体每个类别识别准确率如下:name== yin123 acc: 1.0 name== liu123 acc: 0.9855072463768116 name== yu123 acc: 1.0 name== ma123 acc: 0.9821428571428571 name== zhou123 acc: 0.9912280701754386 name== wang123 acc: 1.0 name== xu123 acc: 1.0 name== taojinglong acc: 0.8529411764705882
-
实时检测
设备描述:8g内存+i7+gtx960m+自带摄像头
详细代码如face_recognition.py
检测效果如图:
-
备注
-