机器学习之人脸识别face_recognition使用
機器學習之人臉識別face_recognition使用
- 簡介
- 一
- 二
- 主要方法介紹
- 1. load_image_file 加載圖像
- 2. face_locations 定位圖中所有人臉
- 3. face_landmarks 識別人臉關鍵點
- 4. face_encodings 獲取圖像文件中所有面部編碼
- 5. compare_faces 由面部編碼匹配臉
- 實踐
- demo1:識別人臉特征并打印出來
- demo2 : 識別圖片中的所有人臉并顯示
- demo3 : 顯示未知圖片中已知人物的臉
- demo4 : 攝像頭頭像識別
- demo5人臉識別簽到系統
- 謝謝大家,如有需要,請聯系我
- 郵箱為zeuskkk@163.com
簡介
一
face_recognition項目是世界上最簡潔的人臉識別庫,可以使用Python和命令行工具提取、識別、操作人臉。
本項目的人臉識別是基于業內領先的C++開源庫 dlib中的深度學習模型,用Labeled Faces in the Wild人臉數據集進行測試,有高達99.38%的準確率。但對小孩和亞洲人臉的識別準確率尚待提升。
Labeled Faces in the Wild是美國麻省大學安姆斯特分校(University of Massachusetts Amherst)制作的人臉數據集,該數據集包含了從網絡收集的13,000多張面部圖像。
本項目提供了簡易的face_recognition命令行工具
二
人臉識別實際上是對人臉進行編碼后再去計算兩兩人臉的相似度,known_image是已知人臉庫的圖像,unknown_image是待檢測的圖像,分別利用face_encodings函數來映射成一個向量,再利用兩個向量的內積來衡量相似度,compare_faces函數就是根據閾值確認是否是同一人臉。上述函數都是支持多個人臉計算的。另外compare_faces有個tolerance參數是控制閾值的,tolerance值越低越嚴格,默認為0.6。
主要方法介紹
1. load_image_file 加載圖像
import face_recognition之后直接調用face_recognition.load_image_file()讀入圖像,參數給文件名字符串,注意:jpg文件要和程序放在同一個文件夾下。輸出圖像是rgb格式(opencv中是bgr格式)。
import face_recognition #加載圖像文件 image = face_recognition.load_image_file("your_file.jpg")2. face_locations 定位圖中所有人臉
加載圖像文件后直接調用face_recognition.face_locations(image),能定位所有圖像中識別出的人臉位置信息,返回值是列表形式,列表中每一行是一張人臉的位置信息,包括[top, right, bottom, left],也可理解為每個人臉是一個tuple存儲,分別代表框住人臉的矩形中左上角和右下角的坐標(x1,y1,x2,y2)。可遍歷列表打印出每張臉的位置信息,也可以通過位置信息截出識別出的人臉的圖像顯示出來,代碼如下:
#定位所有找到的臉的位置 face_locations = face_recognition.face_locations(image) # 循環找到的所有人臉 for face_location in face_locations:# 打印每張臉的位置信息top, right, bottom, left = face_locationprint("A face is located at pixel location Top: {}, Left: {}, Bottom: {}, Right: {}".format(top, left, bottom, right))# 指定人臉的位置信息,然后顯示人臉圖片face_image = image[top:bottom, left:right]pil_image = Image.fromarray(face_image)pil_image.show()3. face_landmarks 識別人臉關鍵點
加載圖像后,調用face_recognition.face_landmarks(image)可識別出人臉關鍵點信息,包括眼睛、鼻子、嘴巴和下巴等,參數仍是加載的圖像image,返回值是包含面部特征字典的列表,列表中每一項對應一張人臉,包括nose_bridge、right_eyebrow、right_eye、chine、left_eyebrow、bottom_lip、nose_tip、top_lip、left_eye幾個部分,每個部分包含若干個特征點(x,y),總共有68個特征點。列表長度就是圖中識別出的人臉數,可遍歷此列表和字典的鍵值對,打印出所有面部特征點,也可在圖像上畫出來,代碼如下:
from PIL import Image, ImageDraw face_landmarks_list = face_recognition.face_landmarks(image) pil_image = Image.fromarray(image) d = ImageDraw.Draw(pil_image) for face_landmarks in face_landmarks_list:#face_landmarks_list中每個元素都包含以下key的字典#打印此圖像中每個面部特征的位置facial_features = ['chin','left_eyebrow','right_eyebrow','nose_bridge','nose_tip','left_eye','right_eye','top_lip','bottom_lip']for facial_feature in facial_features:print("The {} in this face has the following points: {}".format(facial_feature, face_landmarks[facial_feature]))#在圖像中畫出每個人臉特征!for facial_feature in facial_features:d.line(face_landmarks[facial_feature], width=5) pil_image.show()4. face_encodings 獲取圖像文件中所有面部編碼
face_recognition.face_encodings(image)方法可獲取每個圖像文件中每個面部的面部編碼,參數仍是加載的圖像image,由于每個圖像中可能有多個臉,所以返回的是一個編碼列表,后續訪問時注意加上索引號或者依次遍歷。
由打印可看出每張人臉是一個128維的向量。
5. compare_faces 由面部編碼匹配臉
用face_recognition.compare_faces()方法可匹配兩個面部特征編碼,利用兩個向量的內積來衡量相似度,根據閾值確認是否是同一人臉。
位置參數:第一個參數給出一個面部編碼列表(很多張臉),第二個參數給出單個面部編碼(一張臉),compare_faces方法會將第二個參數的編碼與第一個參數中的編碼依次匹配,返回值是一個布爾值列表,匹配成功的臉返回True,匹配失敗的返回False,順序與第一個參數中臉的順序一致。
默認參數:tolerance=0.6,可根據自己需求更改,tolerance越小匹配越嚴格,例如
matches = face_recognition.compare_faces(known_face_encodings, face_encoding,tolerance=0.39),將閾值改為了0.39,閾值太低容易造成無法成功識別人臉,太高容易造成人臉識別混淆,這個是根據我自己測試后慢慢試出來的一個值。
實踐
demo1:識別人臉特征并打印出來
from PIL import Image, ImageDraw import face_recognition# 將jpg文件加載到numpy 數組中 image = face_recognition.load_image_file("view_Mr_G.jpg")#查找圖像中所有面部的所有面部特征 face_landmarks_list = face_recognition.face_landmarks(image)print("I found {} face(s) in this photograph.".format(len(face_landmarks_list))) pil_image = Image.fromarray(image) d = ImageDraw.Draw(pil_image) for face_landmarks in face_landmarks_list:#打印此圖像中每個面部特征的位置facial_features = ['chin','left_eyebrow','right_eyebrow','nose_bridge','nose_tip','left_eye','right_eye','top_lip','bottom_lip']for facial_feature in facial_features:print("The {} in this face has the following points: {}".format(facial_feature, face_landmarks[facial_feature]))#在圖像中畫出每個人臉特征!for facial_feature in facial_features:d.line(face_landmarks[facial_feature], width=5)pil_image.show()demo2 : 識別圖片中的所有人臉并顯示
from PIL import Image import face_recognition# 將jpg文件加載到numpy 數組中 image = face_recognition.load_image_file("view_Mr_G.jpg")# 使用默認的給予HOG模型查找圖像中所有人臉 # 這個方法已經相當準確了,但還是不如CNN模型那么準確,因為沒有使用GPU加速 # 另請參見: find_faces_in_picture_cnn.py face_locations = face_recognition.face_locations(image)# 使用CNN模型 # face_locations = face_recognition.face_locations(image, number_of_times_to_upsample=0, model="cnn")# 打印:我從圖片中找到了 多少 張人臉 print("I found {} face(s) in this photograph.".format(len(face_locations)))# 循環找到的所有人臉 for face_location in face_locations:# 打印每張臉的位置信息top, right, bottom, left = face_locationprint("A face is located at pixel location Top: {}, Left: {}, Bottom: {}, Right: {}".format(top, left, bottom, right)) # 指定人臉的位置信息,然后顯示人臉圖片face_image = image[top:bottom, left:right]pil_image = Image.fromarray(face_image)pil_image.show()demo3 : 顯示未知圖片中已知人物的臉
# 識別人臉鑒定是哪個人import face_recognition from PIL import Image, ImageDraw import cv2 PATH = "/Users/tanyashi/Python/python project/face_recognition/一起同過窗" VIEW_PIC_NAME="view2.jpg" UNKNOWN_IMAGE="view_Mr_G.jpg" #將jpg文件加載到numpy數組中 view_image = face_recognition.load_image_file(VIEW_PIC_NAME) #要識別的圖片 unknown_image = face_recognition.load_image_file(UNKNOWN_IMAGE) results = [] #獲取每個圖像文件中每個面部的面部編碼 #由于每個圖像中可能有多個面,所以返回一個編碼列表。 #但是由于我知道每個圖像只有一個臉,我只關心每個圖像中的第一個編碼,所以我取索引0。 view_face_encoding = face_recognition.face_encodings(view_image)[0] print("view_face_encoding:{}\n\n".format(view_face_encoding)) known_faces = [view_face_encoding] face_locations = face_recognition.face_locations(unknown_image) print('got {} face(s) in {}:'.format(len(face_locations), UNKNOWN_IMAGE)) for face_location in face_locations:top, right, bottom, left = face_location#print(top, right, bottom, left)face_image = unknown_image[top:bottom, left:right]face_encoding = face_recognition.face_encodings(face_image)if face_encoding:result = {}result['face_encoding'] = face_encodingresult['is_view'] = face_recognition.compare_faces(known_faces, face_encoding[0])[0]result['location'] = face_locationresult['face_id'] = face_locations.index(face_location)results.append(result)if result['is_view']:print('face {} is view!!'.format(result['face_id']+1))#print(top, right, bottom, left) #print("results :{}".format([i['is_view'] for i in results])) print("please find out view in this image:") view_face_location = [i['location'] for i in results if i['is_view']] if view_face_location:top, right, bottom, left = view_face_location[0]#print(top, right, bottom, left)face_image = unknown_image[top:bottom, left:right]pil_image = Image.fromarray(face_image)pil_image.show() else:print('view is not in this pic!')demo4 : 攝像頭頭像識別
# 攝像頭頭像識別 import face_recognition import cv2video_capture = cv2.VideoCapture(0)# 本地圖像 chenduling_image = face_recognition.load_image_file("chenduling.jpg") chenduling_face_encoding = face_recognition.face_encodings(chenduling_image)[0]# 本地圖像二 sunyizheng_image = face_recognition.load_image_file("sunyizheng.jpg") sunyizheng_face_encoding = face_recognition.face_encodings(sunyizheng_image)[0]# 本地圖片三 zhangzetian_image = face_recognition.load_image_file("zhangzetian.jpg") zhangzetian_face_encoding = face_recognition.face_encodings(zhangzetian_image)[0]# Create arrays of known face encodings and their names # 臉部特征數據的集合 known_face_encodings = [chenduling_face_encoding,sunyizheng_face_encoding,zhangzetian_face_encoding ]# 人物名稱的集合 known_face_names = ["michong","sunyizheng","chenduling" ]face_locations = [] face_encodings = [] face_names = [] process_this_frame = Truewhile True:# 讀取攝像頭畫面ret, frame = video_capture.read()# 改變攝像頭圖像的大小,圖像小,所做的計算就少small_frame = cv2.resize(frame, (0, 0), fx=0.25, fy=0.25)# opencv的圖像是BGR格式的,而我們需要是的RGB格式的,因此需要進行一個轉換。rgb_small_frame = small_frame[:, :, ::-1]# Only process every other frame of video to save timeif process_this_frame:# 根據encoding來判斷是不是同一個人,是就輸出true,不是為flaseface_locations = face_recognition.face_locations(rgb_small_frame)face_encodings = face_recognition.face_encodings(rgb_small_frame, face_locations)face_names = []for face_encoding in face_encodings:# 默認為unknownmatches = face_recognition.compare_faces(known_face_encodings, face_encoding)name = "Unknown"# if match[0]:# name = "michong"# If a match was found in known_face_encodings, just use the first one.if True in matches:first_match_index = matches.index(True)name = known_face_names[first_match_index]face_names.append(name)process_this_frame = not process_this_frame# 將捕捉到的人臉顯示出來for (top, right, bottom, left), name in zip(face_locations, face_names):# Scale back up face locations since the frame we detected in was scaled to 1/4 sizetop *= 4right *= 4bottom *= 4left *= 4# 矩形框cv2.rectangle(frame, (left, top), (right, bottom), (0, 0, 255), 2)#加上標簽cv2.rectangle(frame, (left, bottom - 35), (right, bottom), (0, 0, 255), cv2.FILLED)font = cv2.FONT_HERSHEY_DUPLEXcv2.putText(frame, name, (left + 6, bottom - 6), font, 1.0, (255, 255, 255), 1)# Displaycv2.imshow('monitor', frame)# 按Q退出if cv2.waitKey(1) & 0xFF == ord('q'):breakvideo_capture.release() cv2.destroyAllWindows()demo5人臉識別簽到系統
# import face_recognition import face_recognition import cv2 import os import numpy as np from PIL import Image, ImageDraw, ImageFont import dlib import datetime import threading # 導入threading模塊 import time from imutils import face_utils from scipy.spatial import distanceimport yagmailclass Recorder:passrecord_dic = {} # 訪問記錄字典 unknownjpg = [] # 保存來訪的陌生人的照片的列表 flagover = 0 # 用于全局判斷是否需要保存來訪信息def sendemail(title, contents, fileslist):yag = yagmail.SMTP(user="2215863456@qq.com", password="agjnddqxmibydjej", host='smtp.qq.com')yag.send('zeuskkk@163.com', title, contents, fileslist)# 雙眼上下眼距檢測 def eye_aspect_ratio(eye):# print(eye)A = distance.euclidean(eye[1], eye[5]) # euclidean是計算歐氏距離B = distance.euclidean(eye[2], eye[4])C = distance.euclidean(eye[0], eye[3])ear = (A + B) / (2.0 * C)return ear# 字典轉換為字符串 def dicttostr():strlist = []listkey = list(sorted(record_dic.keys()))for item in listkey:strlist.extend([item + ',' + str(onetime) for onetime in record_dic[item].times])return strlistdef saveRecorder(name, frame):global record_dicglobal flagoverglobal unknownjpgif flagover == 1:returntry:rec = record_dic[name]secondsDiff = (datetime.datetime.now() - rec.times[-1]).total_seconds()if secondsDiff < 60 * 10: # 如果兩次比較的時間在10分鐘內將被過濾掉returnrec.times.append(datetime.datetime.now())print('更新記錄', record_dic, rec.times)except (KeyError):newRec = Recorder()newRec.times = [datetime.datetime.now()]record_dic[name] = newRecprint('添加記錄', record_dic, newRec.times)if name == '未知人員':s = str(record_dic[name].times[-1])print('寫入', s[:10] + s[-6:])filename = s[:10] + s[-6:] + '.jpg'cv2.imwrite(filename, frame)unknownjpg.append(filename)def loop_timer_handler(): # 定時器循環觸發函數print('————————Timer headle!————————', str(datetime.datetime.now()))global timer2global flagoverglobal record_dicglobal unknownjpgflagover = 1timer2 = threading.Timer(60 * 1, loop_timer_handler) # 創建定時器 每1分鐘執行一次timer2.start()# 如果mail_content不為空,則發送郵件通知mail_content = '\n'.join(dicttostr())if mail_content.strip(): # 如果有新的記錄內容就發送郵件sendemail("來訪統計記錄", mail_content, unknownjpg)print('來訪登記記錄郵件已發送', mail_content)record_dic.clear()unknownjpg.clear()print("清空")time.sleep(10)print("重新開始")flagover = 0timer2 = threading.Timer(2, loop_timer_handler) timer2.start()def load_img(sample_dir):print('加載已知人員圖片...')for (dirpath, dirnames, filenames) in os.walk(sample_dir): # 一級一級的文件夾遞歸print(dirpath, dirnames, filenames)facelib = []for filename in filenames:filename_path = os.sep.join([dirpath, filename])faceimage = face_recognition.load_image_file(filename_path)# 但是由于我知道每個圖像只有一個臉,我只關心每個圖像中的第一個編碼,所以我取索引0face_encoding = face_recognition.face_encodings(faceimage)[0]facelib.append(face_encoding)return facelib, filenamesdef add_text_cv2(text, left, bottom):'''由于cv2不支持中文顯示,所以在視頻流上顯示中文時,需要先將幀數據轉換成PIL圖像,然后利用PIL來添加中文:param text: 要在圖像上添加的文字 :param left: 添加文字離左邊框的距離:param bottom: 添加文字離下邊框距離:return: '''global frameimg_PIL = Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)) # 轉換圖片格式font = ImageFont.truetype('simhei.ttf', 40) # 加載字體position = (left, bottom) # 指定文字輸出位置draw = ImageDraw.Draw(img_PIL) # 繪制照片draw.text(position, text, font=font, fill=(255, 255, 255)) # 繪制文字frame = cv2.cvtColor(np.asarray(img_PIL), cv2.COLOR_RGB2BGR) # 將圖片轉回OpenCV格式facelib, facename = load_img('../facelib')video_capture = cv2.VideoCapture(0) # 獲得攝像頭face_locations = [] # 定義列表存放人臉位置 face_encodings = [] # 定義列表存放人臉特征編碼 process_this_frame = True # 定義信號量frame_counter = 0 # 連續幀計數 EYE_AR_THRESH = 0.3 # EAR閾值 EYE_AR_CONSEC_FRAMES = 3 # 當EAR小于閾值時,接連多少幀一定發生眨眼動作# 對應特征點的序號 RIGHT_EYE_START = 37 - 1 RIGHT_EYE_END = 42 - 1 LEFT_EYE_START = 43 - 1 LEFT_EYE_END = 48 - 1while True:ret, frame = video_capture.read() # 捕獲一幀圖片small_frame = cv2.resize(frame, (0, 0), fx=0.25, fy=0.25) # 將圖片縮小1/4,為人臉識別提速# opencv的圖像格式默認是BGR格式,大家可以想象成像素排列跟RGB格式不一樣,所以我們必須做一點調整,將像素點進行反向rgb_small_frame = small_frame[:, :, ::-1] # 將opencv的BGR格式轉為RGB格式# 找到這一幀圖像上所有的人臉位置face_locations = face_recognition.face_locations(rgb_small_frame)# 得到面部編碼(見資料文章)face_encodings = face_recognition.face_encodings(rgb_small_frame, face_locations)# print('人臉特征編碼長度', len(face_encodings))face_names = [] # 定義列表,放置識別出來的人員的名字for face_encoding in face_encodings: # 循環多張人臉, 這里一般只有一張人臉matches = face_recognition.compare_faces(facelib, face_encoding, tolerance=0.39)name = "未知人員" # 定義默認的識別結果為Unknown# 有true說明圖片對比已經成功,取出識別的人員名字并開始進行活體眨眼檢測if True in matches: # 如果識別出來,就將名稱取出# 這里matches是個列表,包含每張已知圖片的對比結果,這里應該只有一個為true# 所以我們要找出true的位置,這個位置就是找到的那個人的圖片first_match_index = matches.index(True)# 取出這個人的名字name = facename[first_match_index][:-4] # -4是去掉文件后綴print('開始活體檢測...')# 在圖上加上請眨眼的提示add_text_cv2('{}請眨眼...'.format(name), 0, 0) # 在圖像上添加眨眼提示detector = dlib.get_frontal_face_detector() # 人臉檢測器# 特征檢測算法要做個介紹predictor = dlib.shape_predictor('../libs/shape_predictor_68_face_landmarks.dat') # 人臉特征點檢測器gray = cv2.cvtColor(rgb_small_frame, cv2.COLOR_BGR2GRAY)# 人臉檢測,1代表把圖片像素放大1倍以便能夠搜集到更多的照片細節,返回檢測到所有人臉區域的數組# 這個數不能設置過大,否則影響運行速度rects = detector(gray, 1)if len(rects) > 0:print('#' * 20)shape = predictor(gray, rects[0]) # 檢測特征點,rect[0]代表取第一個人臉# 將所有的臉部坐標點轉換為numpy array的格式# convert the facial landmark (x, y)-coordinates to a NumPy arraypoints = face_utils.shape_to_np(shape)leftEye = points[LEFT_EYE_START:LEFT_EYE_END + 1] # 取出左眼對應的特征點rightEye = points[RIGHT_EYE_START:RIGHT_EYE_END + 1] # 取出右眼對應的特征點leftEAR = eye_aspect_ratio(leftEye) # 計算左眼EARrightEAR = eye_aspect_ratio(rightEye) # 計算右眼EARear = (leftEAR + rightEAR) / 2.0 # 求左右眼EAR的均值# 如果EAR小于閾值,開始計算連續幀,只有連續幀計數超過EYE_AR_CONSEC_FRAMES時,才會計做一次眨眼if ear < EYE_AR_THRESH:frame_counter += 1print('ear小于閾值了!!!', frame_counter)if frame_counter >= EYE_AR_CONSEC_FRAMES:# blink_counter += 1print('眨眼檢測成功,請進入!')frame_counter = 0print('活體檢測結束')face_names.append(name) # 保存識別結果# process_this_frame = not process_this_frame #信號量保護結束(這個語句沒什么用)# 顯示結果for (top, right, bottom, left), name in zip(face_locations, face_names):top *= 4 # 還原人臉的原始尺寸,原來是1/4,現在放到原大小right *= 4bottom *= 4left *= 4# frame:要顯示的幀,(left, top), (right, bottom) 各方向坐標,(0, 0, 255) 人臉框顏色, 2是線條粗細cv2.rectangle(frame, (left, top), (right, bottom), (0, 0, 255), 2) # 標注人臉add_text_cv2(name, left + 6, bottom - 6)saveRecorder(name, frame) # 過濾并保存記錄cv2.imshow('security check', frame) # 顯示圖片檢測框if cv2.waitKey(1) & 0xFF == ord('q'): # 等待鍵盤輸入,當輸入q時,整個程序退出breakvideo_capture.release() # 釋放攝像頭資源 time.sleep(2) # 休眠10秒 timer2.cancel() # 關閉定時器線程謝謝大家,如有需要,請聯系我
郵箱為zeuskkk@163.com
總結
以上是生活随笔為你收集整理的机器学习之人脸识别face_recognition使用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 美间如何生成海报支持AI文本库?美间生成
- 下一篇: 作废发票验旧在电子税务局怎么操作 电子税