博主仍是抱着開源精神,由於下面這些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!