博主仍是抱着开源精神,由于下面这些code是通过了上千次baidu和google搜索出来获得的结果及其想法,提供给你们共同窗习进步,注释的都很清楚,功能彻底实现
先上一下效果图python
(我知道我很帅,请勿吐槽,谢谢.不然请直接exit())git
很长时间没发文了,今天跟你们分享一下关于Python原生的人脸识别(不调用任何第三方的接口),离线版本.
刚开始编写的时候,参考了不少的文章,首先在此先进行感谢一波!github
文章可能讲的比较片面,可是你把我在文章的code copy下去,确定包你能用,识别率能够达到百分之90以上,代码性能有待优化.可是授之以鱼,不如授之以渔.下方我会开始从环境的部署开始讲解.有讲错或者bug的地方,欢迎给我留言.
文章会从所调用的库进行介绍.然后介绍库的安装及部署,但愿你们耐心看:算法
下面将会介绍库的导入,请务必按照文中顺序跟随(文中环境,命令以mac为主)json
完成上述步骤后,首先得恭喜你,完成了opencv,face_recognition,dlib的部署.继续下面的工做,您须要先进行阅读下面的文章:来自Github的 face_recognition介绍,中文翻译为同济大学的 子豪兄Tommy;看完子豪兄Tommy的github翻译以后,请继续看face_recognition的方法介绍,这是通过博主综合评估及踩坑以后力荐的;segmentfault
好的,若是你看完了上述资料,那么我开始给你们讲解此次整我的脸识别程序的流程app
camera = cv2.VideoCapture(0) # 调用笔记本内置摄像头,因此参数为0,若是有其余的摄像头能够调整参数为1,2
predictor = dlib.shape_predictor("lib/shape_predictor_68_face_landmarks.dat")
detector = dlib.get_frontal_face_detector();
5.而后开始while死循环.进行检测.
6.检测到人脸后,生成特征码face_recognition.face_encodings,然后利用face_recognition的compare_faces方法进行比对
7.返回识别结果dom
8.文件目录机器学习
ok,废话已经不少.so,下面直接上code,首先从功能性示范开始(代码注释的已经很是详细了,由于我是python菜鸡)
import numpy as np; import cv2; import dlib; camera = cv2.VideoCapture(0) # 调用笔记本内置摄像头,因此参数为0,若是有其余的摄像头能够调整参数为1,2 # 注释掉opencv的面部分类识别器,由于感受不是很好使 # detector = cv2.CascadeClassifier('lib/haarcascade_frontalface_default.xml') # 加载面部识别的分类器 # 改用dlib的面部识别 detector = dlib.get_frontal_face_detector(); # 调用dlib的面部68点识别训练库文件 predictor = dlib.shape_predictor("lib/shape_predictor_68_face_landmarks.dat") while True: result, img = camera.read() # 由于read方法反回了两个变量.因此须要定义两个变量进行接收该方法的返回值 # exit(); gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 转换图片为灰度 faces = detector(gray, 1) # 检测出人脸数 # len(faces) > 1 # 利用cv2.putText输出 for i in range(len(faces)): landmarks = np.matrix([[p.x, p.y] for p in predictor(img, faces[i]).parts()]) # enumerate是一个Python的内置方法,用于遍历索引 # index是序号;face是dets中取出的dlib.rectangle类的对象,包含了人脸的区域等信息 # left()、top()、right()、bottom()都是dlib.rectangle类的方法,对应矩形四条边的位置 for index, face in enumerate(faces): # 这里画出人脸框 left = face.left() top = face.top() right = face.right() bottom = face.bottom() cv2.rectangle(img, (left, top), (right, bottom), (0, 255, 0), 3) shape = predictor(img, face) # 寻找人脸的68个标定点 print(shape) print(shape.num_parts) # 遍历全部点,打印出其坐标,并用蓝色的圈表示出来 for index, pt in enumerate(shape.parts()): print('Part {}: {}'.format(index, pt)) pt_pos = (pt.x, pt.y) cv2.circle(img, pt_pos, 2, (0, 255, 0), 1) cv2.imshow('frame', img) # 展现 if cv2.waitKey(1) & 0xFF == ord('q'): # 监听键盘 每一秒检测一下是否按下了Q. break else: pass camera.release() # 释放摄像头资源 cv2.destroyAllWindows(); # 关闭全部弹出的窗口
下面的是人脸采集
import numpy as np import cv2 import dlib import face_recognition # 注释掉opencv的面部分类识别器,由于感受不是很好使 # detector = cv2.CascadeClassifier('xml/haarcascade_frontalface_default.xml') # 改用dlib的面部识别 detector = dlib.get_frontal_face_detector() # 调用dlib的面部68点识别训练库文件 predictor = dlib.shape_predictor("lib/shape_predictor_68_face_landmarks.dat") camera = cv2.VideoCapture(0) # 调用笔记本内置摄像头,因此参数为0,若是有其余的摄像头能够调整参数为1,2 i = 0 # 设置计步器 UID = input('enter your id: ') while True: result, img = camera.read() # 接收噶你方法返回的结果 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 转换为灰度 faces = detector(gray, 1) # 检测出人脸数 if len(faces) == 1: for index, face in enumerate(faces): left = face.left() top = face.top() right = face.right() bottom = face.bottom() cv2.rectangle(img, (left, top), (right, bottom), (0, 255, 0), 3) # 画出框子 i += 1 #计步器自增 cv2.imwrite("img/user." + str(UID) + '.' + str(i) + ".jpg", gray[top:bottom, left:right]) # 存储照片 cv2.imshow('frame', img) # 展现图片 else: cv2.putText(img, "Warning: can only appear for one person", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2) cv2.imshow('frame', img) if cv2.waitKey(100) & 0xFF == ord('q'): #每秒检查是否按下Q break elif i >= 20: # 20次后自动退出 break camera.release() cv2.destroyAllWindows()
下面的是人脸训练
import cv2 import os import numpy as np from PIL import Image import face_recognition import json def get_images_and_labels(path): image_paths = [os.path.join(path, f) for f in os.listdir(path)] # print(image_paths); faces = [] for src in image_paths: data = {} img = cv2.imread(src) list_of_face_encodings = face_recognition.face_encodings(img) # print(list_of_face_encodings) if len(list_of_face_encodings): data['face'] = list_of_face_encodings[0].tolist() image_id = int(src.split('.')[1]) data['id'] = image_id # print(data) faces.append(data) print(faces) return faces result = get_images_and_labels('img') # print(result);exit(); # print(json.jumps(result)) with open("data/data.json", "w") as f: json.dump(result, f, sort_keys=True, indent=4, ensure_ascii=False) print("加载入文件完成...")
人脸识别
import cv2 import numpy as np import dlib import face_recognition import json def bejson(): f = open("data/data.json", encoding='utf-8') # 设置以utf-8解码模式读取文件,encoding参数必须设置,不然默认以gbk模式读取文件,当文件中包含中文时,会报错 data = json.load(f) faces = [] ids = [] for value in data: faces.append(np.asarray(value['face'])); ids.append(value['id']); return ids, faces camera = cv2.VideoCapture(0) # 调用笔记本内置摄像头,因此参数为0,若是有其余的摄像头能够调整参数为1,2 # 改用dlib的面部识别 detector = dlib.get_frontal_face_detector() # 调用dlib的面部68点识别训练库文件 predictor = dlib.shape_predictor("lib/shape_predictor_68_face_landmarks.dat") font = cv2.FONT_HERSHEY_SIMPLEX def max_count(lt): # 定义一个字典,记录元素及次数 d = {} # 记录最大次数的元素 max_key = None for i in lt: # 判断字典中是否没有该元素 if i not in d: # 计算该元素在列表中出现的次数 count = lt.count(i) # 保存到字典中 d[i] = count # 记录最大元素 if count > d.get(max_key, 0): max_key = i # for key in d: # if d.get(max_key, 0) < d[key]: # max_key = key return max_key while True: result, img = camera.read() # 由于read方法反回了两个变量.因此须要定义两个变量进行接收该方法的返回值 # exit(); gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 转换图片为灰度 faces = detector(gray, 1) # 检测出人脸数 if len(faces) == 1: # print(face_recognition.face_encodings(img)) face_encoding_to_check = face_recognition.face_encodings(img) # print(face_encoding_to_check[0]);exit() # 读取json ids,data = bejson(); # print(data);exit(); result = face_recognition.compare_faces( data, face_encoding_to_check[0], tolerance=0.4) print(result) uidArray = [] # 识别经过的id for index, value in enumerate(result): # print(value) if value: uidArray.append(index); # print(uidArray) if uidArray: key = max_count(uidArray) # 根据索引找到json中的这我的的id # print(ids[key]) cv2.putText(img, "Verify Success User: No--" + str(ids[key])+"--", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 0), 2) else: cv2.putText(img, "Verify Fail-2", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 0), 2) # 利用cv2.putText输出 for i in range(len(faces)): landmarks = np.matrix([[p.x, p.y] for p in predictor(img, faces[i]).parts()]) # enumerate是一个Python的内置方法,用于遍历索引 # index是序号;face是dets中取出的dlib.rectangle类的对象,包含了人脸的区域等信息 # left()、top()、right()、bottom()都是dlib.rectangle类的方法,对应矩形四条边的位置 for index, face in enumerate(faces): # 这里画出人脸框 left = face.left() top = face.top() right = face.right() bottom = face.bottom() cv2.rectangle(img, (left, top), (right, bottom), (0, 255, 0), 3) shape = predictor(img, face) # 寻找人脸的68个标定点 # print(shape) # print(shape.num_parts) # 遍历全部点,打印出其坐标,并用蓝色的圈表示出来 for index, pt in enumerate(shape.parts()): # print('Part {}: {}'.format(index, pt)) pt_pos = (pt.x, pt.y) cv2.circle(img, pt_pos, 2, (0, 255, 0), 1) else: cv2.putText(img, "Warning: can only appear for one person", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2) cv2.imshow('face verify-3', img) if cv2.waitKey(10) & 0xFF == ord('q'): break camera.release() cv2.destroyAllWindows()
由于博主并非很精通python,若是有不太ok的地方,望谅解.仅供学习!ide
happy coding! bye see you!