0. 引言html
利用 Python 開發,藉助 Dlib 庫捕獲攝像頭中的人臉,提取人臉特徵,經過計算特徵值之間的歐氏距離,來和預存的人臉特徵進行對比,判斷是否匹配,達到人臉識別的目的;python
能夠從攝像頭中摳取人臉圖片存儲到本地,而後提取構建預設人臉特徵;git
根據摳取的 / 已有的同一我的多張人臉圖片提取 128D 特徵值,而後計算該人的 128D 特徵均值;github
而後和攝像頭中實時獲取到的人臉提取出的特徵值,計算歐氏距離,斷定是否爲同一張人臉; 數據庫
Python + OpenCv + Dlib ; windows
1. 人臉檢測數組
faces = detector(img_gray, 0) -> <class 'dlib.dlib.rectangles'> -> app
2. 計算特徵點ide
shape = predictor(img_rd, faces[i]) -> <class 'dlib.dlib.full_object_detection'> -> 函數
3. 特徵描述子
facerec.compute_face_descriptor(img_rd, shape) -> <class 'dlib.dlib.vector'>
博客中代碼以 GitHub 爲準,博客中可能沒有更新;
# Blog : http://www.cnblogs.com/AdaminXie
# GitHub : https://github.com/coneypo/Dlib_face_recognition_from_camera
Features :
人臉識別 / Face Recognition 的說明:
Wikipedia 上關於人臉識別系統 / Face Recognition System 的描述:they work by comparing selected facial features from given image with faces within a database.
本項目中就是比較 預設的人臉的特徵 和 攝像頭實時獲取到的人臉的特徵 ;
核心就是 提取 128D 人臉特徵,而後計算 攝像頭人臉特徵 和 預設的特徵臉的歐式距離,進行比對;
效果以下:
圖 1 攝像頭多我的臉時識別效果
1. 整體流程
先說下 人臉檢測 ( Face detection ) 和 人臉識別 ( Face Recognition ) ,前者是達到檢測出場景中人臉的目的就能夠了,然後者不只須要檢測出人臉,還要和已有人臉數據進行比對,識別出是否在數據庫中,或者進行身份標註之類處理,人臉檢測和人臉識別二者有時候可能會被理解混淆;
個人以前一些項目都是用 Dlib 作人臉檢測這塊,這個項目想要實現的功能是人臉識別功能,藉助的是 Dlib 官網中 face_recognition.py 這個例程 ( Link:http://dlib.net/face_recognition.py.html );
核心在於 利用「dlib_face_recognition_resnet_model_v1.dat」 這個 model,提取人臉圖像的 128D 特徵,而後比對不一樣人臉圖片的 128D 特徵,設定閾值 計算歐氏距離 來判斷是否爲同一張臉;
1 # face recognition model, the object maps human faces into 128D vectors
2 facerec = dlib.face_recognition_model_v1("dlib_face_recognition_resnet_model_v1.dat") 3
4 shape = predictor(img, dets[0]) 5 face_descriptor = facerec.compute_face_descriptor(img, shape)
圖 2 整體設計流程
2.源碼介紹
主要有
這三個 Python 文件,接下來會分別介紹實現功能;
2.1 get_faces_from_camera.py / 人臉註冊錄入
人臉識別須要將 提取到的圖像數據 和 已有圖像數據 進行比對分析,因此這部分代碼實現的功能就是 人臉錄入;
程序會生成一個窗口,顯示調用的攝像頭實時獲取的圖像;
(關於攝像頭的調用方式能夠參考這裏: Python 3 利用 Dlib 19.7 實現攝像頭人臉檢測特徵點標定);
而後根據鍵盤輸入進行人臉捕獲:
攝像頭的調用是利用 opencv 庫的 cv2.VideoCapture(0), 此處參數爲 0 表明調用的是筆記本的默認攝像頭,你也可讓它調用傳入已有視頻文件;
圖 3 get_face_from_camera.py 的界面
捕獲到的一組人臉示例;
圖 4 捕獲到的一組人臉
1 # 進行人臉錄入 / face register 2 # 錄入多張人臉 / support multi-faces 3 4 # Author: coneypo 5 # Blog: http://www.cnblogs.com/AdaminXie 6 # GitHub: https://github.com/coneypo/Dlib_face_recognition_from_camera 7 # Mail: coneypo@foxmail.com 8 9 # Created at 2018-05-11 10 # Updated at 2019-03-23 11 12 import dlib # 人臉處理的庫 Dlib 13 import numpy as np # 數據處理的庫 Numpy 14 import cv2 # 圖像處理的庫 OpenCv 15 16 import os # 讀寫文件 17 import shutil # 讀寫文件 18 19 # Dlib 正向人臉檢測器 / frontal face detector 20 detector = dlib.get_frontal_face_detector() 21 22 # Dlib 68 點特徵預測器 / 68 points features predictor 23 predictor = dlib.shape_predictor('data/data_dlib/shape_predictor_68_face_landmarks.dat') 24 25 # OpenCv 調用攝像頭 use camera 26 cap = cv2.VideoCapture(0) 27 28 # 設置視頻參數 set camera 29 cap.set(3, 480) 30 31 # 人臉截圖的計數器 the counter for screen shoot 32 cnt_ss = 0 33 34 # 存儲人臉的文件夾 the folder to save faces 35 current_face_dir = "" 36 37 # 保存 photos/csv 的路徑 the directory to save photos/csv 38 path_photos_from_camera = "data/data_faces_from_camera/" 39 path_csv_from_photos = "data/data_csvs_from_camera/" 40 41 42 # 新建保存人臉圖像文件和數據CSV文件夾 43 # mkdir for saving photos and csv 44 def pre_work_mkdir(): 45 46 # 新建文件夾 / make folders to save faces images and csv 47 if os.path.isdir(path_photos_from_camera): 48 pass 49 else: 50 os.mkdir(path_photos_from_camera) 51 if os.path.isdir(path_csv_from_photos): 52 pass 53 else: 54 os.mkdir(path_csv_from_photos) 55 56 57 pre_work_mkdir() 58 59 60 ##### optional/可選, 默認關閉 ##### 61 # 刪除以前存的人臉數據文件夾 62 # delete the old data of faces 63 def pre_work_del_old_face_folders(): 64 # 刪除以前存的人臉數據文件夾 65 # 刪除 "/data_faces_from_camera/person_x/"... 66 folders_rd = os.listdir(path_photos_from_camera) 67 for i in range(len(folders_rd)): 68 shutil.rmtree(path_photos_from_camera+folders_rd[i]) 69 70 csv_rd = os.listdir(path_csv_from_photos) 71 for i in range(len(csv_rd)): 72 os.remove(path_csv_from_photos+csv_rd[i]) 73 74 # 這裏在每次程序錄入以前, 刪掉以前存的人臉數據 75 # 若是這裏打開,每次進行人臉錄入的時候都會刪掉以前的人臉圖像文件夾 76 # pre_work_del_old_face_folders() 77 ################################## 78 79 80 # 若是有以前錄入的人臉 81 # 在以前 person_x 的序號按照 person_x+1 開始錄入 82 # if old face exists, start from person_x+1 83 if os.listdir("data/data_faces_from_camera/"): 84 # 獲取已錄入的最後一我的臉序號 85 person_list = os.listdir("data/data_faces_from_camera/") 86 person_list.sort() 87 person_num_latest = int(str(person_list[-1]).split("_")[-1]) 88 person_cnt = person_num_latest 89 90 # 若是第一次存儲或者沒有以前錄入的人臉, 按照 person_1 開始錄入 91 # start from person_1 92 else: 93 person_cnt = 0 94 95 # 以後用來控制是否保存圖像的 flag / the flag to control if save 96 save_flag = 1 97 98 # 以後用來檢查是否先按 'n' 再按 's' / the flag to check if press 'n' before 's' 99 press_n_flag = 0 100 101 while cap.isOpened(): 102 # 480 height * 640 width 103 flag, img_rd = cap.read() 104 kk = cv2.waitKey(1) 105 106 img_gray = cv2.cvtColor(img_rd, cv2.COLOR_RGB2GRAY) 107 108 # 人臉數 faces 109 faces = detector(img_gray, 0) 110 111 # 待會要寫的字體 / font to write 112 font = cv2.FONT_HERSHEY_COMPLEX 113 114 # 按下 'n' 新建存儲人臉的文件夾 / press 'n' to create the folders for saving faces 115 if kk == ord('n'): 116 person_cnt += 1 117 current_face_dir = path_photos_from_camera + "person_" + str(person_cnt) 118 os.makedirs(current_face_dir) 119 print('\n') 120 print("新建的人臉文件夾 / Create folders: ", current_face_dir) 121 122 cnt_ss = 0 # 將人臉計數器清零 / clear the cnt of faces 123 press_n_flag = 1 # 已經按下 'n' / have pressed 'n' 124 125 # 檢測到人臉 / if face detected 126 if len(faces) != 0: 127 # 矩形框 128 # show the rectangle box 129 for k, d in enumerate(faces): 130 # 計算矩形大小 131 # we need to compute the width and height of the box 132 # (x,y), (寬度width, 高度height) 133 pos_start = tuple([d.left(), d.top()]) 134 pos_end = tuple([d.right(), d.bottom()]) 135 136 # 計算矩形框大小 / compute the size of rectangle box 137 height = (d.bottom() - d.top()) 138 width = (d.right() - d.left()) 139 140 hh = int(height/2) 141 ww = int(width/2) 142 143 # 設置顏色 / the color of rectangle of faces detected 144 color_rectangle = (255, 255, 255) 145 if (d.right()+ww) > 640 or (d.bottom()+hh > 480) or (d.left()-ww < 0) or (d.top()-hh < 0): 146 cv2.putText(img_rd, "OUT OF RANGE", (20, 300), font, 0.8, (0, 0, 255), 1, cv2.LINE_AA) 147 color_rectangle = (0, 0, 255) 148 save_flag = 0 149 else: 150 color_rectangle = (255, 255, 255) 151 save_flag = 1 152 153 cv2.rectangle(img_rd, 154 tuple([d.left() - ww, d.top() - hh]), 155 tuple([d.right() + ww, d.bottom() + hh]), 156 color_rectangle, 2) 157 158 # 根據人臉大小生成空的圖像 / create blank image according to the size of face detected 159 im_blank = np.zeros((int(height*2), width*2, 3), np.uint8) 160 161 if save_flag: 162 # 按下 's' 保存攝像頭中的人臉到本地 / press 's' to save faces into local images 163 if kk == ord('s'): 164 # 檢查有沒有先按'n'新建文件夾 / check if you have pressed 'n' 165 if press_n_flag: 166 cnt_ss += 1 167 for ii in range(height*2): 168 for jj in range(width*2): 169 im_blank[ii][jj] = img_rd[d.top()-hh + ii][d.left()-ww + jj] 170 cv2.imwrite(current_face_dir + "/img_face_" + str(cnt_ss) + ".jpg", im_blank) 171 print("寫入本地 / Save into:", str(current_face_dir) + "/img_face_" + str(cnt_ss) + ".jpg") 172 else: 173 print("請在按 'S' 以前先按 'N' 來建文件夾 / Please press 'N' before 'S'") 174 175 # 顯示人臉數 / show the numbers of faces detected 176 cv2.putText(img_rd, "Faces: " + str(len(faces)), (20, 100), font, 0.8, (0, 255, 0), 1, cv2.LINE_AA) 177 178 # 添加說明 / add some statements 179 cv2.putText(img_rd, "Face Register", (20, 40), font, 1, (0, 0, 0), 1, cv2.LINE_AA) 180 cv2.putText(img_rd, "N: New face folder", (20, 350), font, 0.8, (0, 0, 0), 1, cv2.LINE_AA) 181 cv2.putText(img_rd, "S: Save current face", (20, 400), font, 0.8, (0, 0, 0), 1, cv2.LINE_AA) 182 cv2.putText(img_rd, "Q: Quit", (20, 450), font, 0.8, (0, 0, 0), 1, cv2.LINE_AA) 183 184 # 按下 'q' 鍵退出 / press 'q' to exit 185 if kk == ord('q'): 186 break 187 188 # 若是須要攝像頭窗口大小可調 / uncomment this line if you want the camera window is resizeable 189 # cv2.namedWindow("camera", 0) 190 191 cv2.imshow("camera", img_rd) 192 193 # 釋放攝像頭 / release camera 194 cap.release() 195 196 cv2.destroyAllWindows()
考慮到有可能須要保存的矩形框超出攝像頭範圍,對於這種異常,若是矩形框超出範圍,矩形框會從白變紅,而後提示 "OUT OF RANGE";
圖 5 人臉錄入異常處理
get_face_from_camera.py 的輸出 log
新建的人臉文件夾 / Create folders: data/data_faces_from_camera/person_1 寫入本地 / Save into: data/data_faces_from_camera/person_1/img_face_1.jpg 寫入本地 / Save into: data/data_faces_from_camera/person_1/img_face_2.jpg 寫入本地 / Save into: data/data_faces_from_camera/person_1/img_face_3.jpg 寫入本地 / Save into: data/data_faces_from_camera/person_1/img_face_4.jpg 新建的人臉文件夾 / Create folders: data/data_faces_from_camera/person_2 寫入本地 / Save into: data/data_faces_from_camera/person_2/img_face_1.jpg 寫入本地 / Save into: data/data_faces_from_camera/person_2/img_face_2.jpg 新建的人臉文件夾 / Create folders: data/data_faces_from_camera/person_3 寫入本地 / Save into: data/data_faces_from_camera/person_3/img_face_1.jpg 寫入本地 / Save into: data/data_faces_from_camera/person_3/img_face_2.jpg
2.2 features_extraction_to_csv.py / 將圖像文件中人臉數據提取出來存入 CSV
這部分代碼實現的功能是將以前捕獲到的人臉圖像文件,提取出 128D 特徵,而後計算出某人人臉數據的特徵均值存入 CSV 中,方便以後識別時候進行比對;
利用 numpy.mean() 計算特徵均值;
features_extraction_to_csv.py 源碼:
1 # 從人臉圖像文件中提取人臉特徵存入 CSV 2 # Features extraction from images and save into features_all.csv 3 4 # Author: coneypo 5 # Blog: http://www.cnblogs.com/AdaminXie 6 # GitHub: https://github.com/coneypo/Dlib_face_recognition_from_camera 7 # Mail: coneypo@foxmail.com 8 9 # Created at 2018-05-11 10 # Updated at 2019-04-04 11 12 # return_128d_features() 獲取某張圖像的128D特徵 13 # compute_the_mean() 計算128D特徵均值 14 15 import cv2 16 import os 17 import dlib 18 from skimage import io 19 import csv 20 import numpy as np 21 22 # 要讀取人臉圖像文件的路徑 23 path_images_from_camera = "data/data_faces_from_camera/" 24 25 # Dlib 正向人臉檢測器 26 detector = dlib.get_frontal_face_detector() 27 28 # Dlib 人臉預測器 29 predictor = dlib.shape_predictor("data/data_dlib/shape_predictor_5_face_landmarks.dat") 30 31 # Dlib 人臉識別模型 32 # Face recognition model, the object maps human faces into 128D vectors 33 face_rec = dlib.face_recognition_model_v1("data/data_dlib/dlib_face_recognition_resnet_model_v1.dat") 34 35 36 # 返回單張圖像的 128D 特徵 37 def return_128d_features(path_img): 38 img_rd = io.imread(path_img) 39 img_gray = cv2.cvtColor(img_rd, cv2.COLOR_BGR2RGB) 40 faces = detector(img_gray, 1) 41 42 print("%-40s %-20s" % ("檢測到人臉的圖像 / image with faces detected:", path_img), '\n') 43 44 # 由於有可能截下來的人臉再去檢測,檢測不出來人臉了 45 # 因此要確保是 檢測到人臉的人臉圖像 拿去算特徵 46 if len(faces) != 0: 47 shape = predictor(img_gray, faces[0]) 48 face_descriptor = face_rec.compute_face_descriptor(img_gray, shape) 49 else: 50 face_descriptor = 0 51 print("no face") 52 53 return face_descriptor 54 55 56 # 將文件夾中照片特徵提取出來, 寫入 CSV 57 def return_features_mean_personX(path_faces_personX): 58 features_list_personX = [] 59 photos_list = os.listdir(path_faces_personX) 60 if photos_list: 61 for i in range(len(photos_list)): 62 # 調用return_128d_features()獲得128d特徵 63 print("%-40s %-20s" % ("正在讀的人臉圖像 / image to read:", path_faces_personX + "/" + photos_list[i])) 64 features_128d = return_128d_features(path_faces_personX + "/" + photos_list[i]) 65 # print(features_128d) 66 # 遇到沒有檢測出人臉的圖片跳過 67 if features_128d == 0: 68 i += 1 69 else: 70 features_list_personX.append(features_128d) 71 else: 72 print("文件夾內圖像文件爲空 / Warning: No images in " + path_faces_personX + '/', '\n') 73 74 # 計算 128D 特徵的均值 75 # N x 128D -> 1 x 128D 76 if features_list_personX: 77 features_mean_personX = np.array(features_list_personX).mean(axis=0) 78 else: 79 features_mean_personX = '0' 80 81 return features_mean_personX 82 83 84 # 讀取某人全部的人臉圖像的數據 85 people = os.listdir(path_images_from_camera) 86 people.sort() 87 88 with open("data/features_all.csv", "w", newline="") as csvfile: 89 writer = csv.writer(csvfile) 90 for person in people: 91 print("##### " + person + " #####") 92 # Get the mean/average features of face/personX, it will be a list with a length of 128D 93 features_mean_personX = return_features_mean_personX(path_images_from_camera + person) 94 writer.writerow(features_mean_personX) 95 print("特徵均值 / The mean of features:", list(features_mean_personX)) 96 print('\n') 97 print("全部錄入人臉數據存入 / Save all the features of faces registered into: data/features_all.csv")
咱們能夠看下對於某張圖片,face_descriptor 這個 128D vectors 的輸出結果:
綠色框內是咱們的返回 128D 特徵的函數;
在紅色框內調用該函數來計算 img_face_13.jpg;
能夠看到黃色框中的輸出爲 128D 的向量;
圖 6 返回單張圖像的 128D 特徵的計算結果
以後就須要人臉圖像進行批量化操做,提取出 128D 的特徵,而後計算特徵均值,存入 features_all.csv;
features_all.csv 是一個 n 行 128 列的 CSV, n 是錄入的人臉數,128 列是某人的 128D 特徵;
這存儲的就是 錄入的人臉數據,以後 攝像頭捕獲的人臉 將要拿過來和 這些特徵值 進行比對,若是歐式距離比較近的話,就能夠認爲是同一張人臉;
get_features_into_CSV.py 的輸出 log:
##### person_1 ##### data/data_csvs_from_camera/person_1.csv 正在讀的人臉圖像 / image to read: data/data_faces_from_camera/person_1/img_face_1.jpg 檢測到人臉的圖像 / image with faces detected: data/data_faces_from_camera/person_1/img_face_1.jpg 正在讀的人臉圖像 / image to read: data/data_faces_from_camera/person_1/img_face_2.jpg 檢測到人臉的圖像 / image with faces detected: data/data_faces_from_camera/person_1/img_face_2.jpg 正在讀的人臉圖像 / image to read: data/data_faces_from_camera/person_1/img_face_3.jpg 檢測到人臉的圖像 / image with faces detected: data/data_faces_from_camera/person_1/img_face_3.jpg 正在讀的人臉圖像 / image to read: data/data_faces_from_camera/person_1/img_face_4.jpg 檢測到人臉的圖像 / image with faces detected: data/data_faces_from_camera/person_1/img_face_4.jpg ##### person_2 ##### data/data_csvs_from_camera/person_2.csv 正在讀的人臉圖像 / image to read: data/data_faces_from_camera/person_2/img_face_1.jpg 檢測到人臉的圖像 / image with faces detected: data/data_faces_from_camera/person_2/img_face_1.jpg 正在讀的人臉圖像 / image to read: data/data_faces_from_camera/person_2/img_face_2.jpg 檢測到人臉的圖像 / image with faces detected: data/data_faces_from_camera/person_2/img_face_2.jpg ##### person_3 ##### data/data_csvs_from_camera/person_3.csv 正在讀的人臉圖像 / image to read: data/data_faces_from_camera/person_3/img_face_1.jpg 檢測到人臉的圖像 / image with faces detected: data/data_faces_from_camera/person_3/img_face_1.jpg 正在讀的人臉圖像 / image to read: data/data_faces_from_camera/person_3/img_face_2.jpg 檢測到人臉的圖像 / image with faces detected: data/data_faces_from_camera/person_3/img_face_2.jpg ...
2.3 face_reco_from_camera.py / 實時人臉識別對比分析
這部分源碼實現的功能:調用攝像頭,捕獲攝像頭中的人臉,而後若是檢測到人臉,將 攝像頭中的人臉提取出 128D 的特徵,而後和 以前錄入人臉的 128D 特徵 進行計算歐式距離,若是比較小,能夠斷定爲一我的,不然不是一我的;
僞代碼以下:
# 人臉檢測器/預測器/識別模型 detector = dlib.get_frontal_face_detector() predictor = dlib.shape_predictor('data/data_dlib/shape_predictor_68_face_landmarks.dat') facerec = dlib.face_recognition_model_v1("data/data_dlib/dlib_face_recognition_resnet_model_v1.dat") faces = detector(img_gray, 0) # 若是檢測到人臉 if len(faces) != 0: # 遍歷全部檢測到的人臉 for i in range(len(faces)): # 進行人臉比對 shape = predictor(img_rd, faces[i]) facerec.compute_face_descriptor(img_rd, shape)
關於用到的 dlib 檢測器,預測器,識別器:
1. dlib.get_frontal_face_detector
Link:
http://dlib.net/python/index.html#dlib.get_frontal_face_detector
簡介 / intro:
返回默認的人臉檢測器,爲下面的 fhog_object_detectorm / Returns the default face detector
2. class dlib.fhog_object_detector
Link:
http://dlib.net/python/index.html#dlib.fhog_object_detector
簡介 / intro:
基於滑動窗的HOG進行目標檢測;
This object represents a sliding window histogram-of-oriented-gradients based object detector.
參數 / parameters:
__call__(self: dlib.fhog_object_detector, image: array, upsample_num_times: int=0L) → dlib.rectangles
3. class dlib.shape_predictor
Link:
http://dlib.net/python/index.html#dlib.shape_predictor
簡介 / intro:
人臉圖像做爲輸入, 輸出面部特徵點;
This object is a tool that takes in an image region containing some object and outputs a set of point locations that define the pose of the object.
The classic example of this is human face pose prediction, where you take an image of a human face as input and are expected to identify
the locations of important facial landmarks such as the corners of the mouth and eyes, tip of the nose, and so forth.
參數 / parameters:
__call__(self: dlib.shape_predictor, image: array, box: dlib.rectangle) → dlib.full_object_detection
輸入: dlib.rectangle 輸出: dlib.full_object_detection
4. class dlib.face_recognition_model_v1
Link:
http://dlib.net/python/index.html#dlib.face_recognition_model_v1
簡介 / intro:
將人臉轉換爲128D特徵向量, 這樣的話類似人臉會比較相近, 不相像的會比較遠;
This object maps human faces into 128D vectors where pictures of the same person are mapped near to each other and pictures of different people are mapped far apart.
The constructor loads the face recognition model from a file. The model file is available here: http://dlib.net/files/dlib_face_recognition_resnet_model_v1.dat.bz2
參數 / parameters:
compute_face_descriptor(self: dlib.face_recognition_model_v1, img: numpy.ndarray[(rows,cols,3),uint8], face: dlib.full_object_detection, num_jitters: int=0L, padding: float=0.25) -> dlib.vector
經過 print(type()) 能夠更清楚的看到 dlib 對象的傳遞:
# 人臉檢測器/預測器/識別模型 detector = dlib.get_frontal_face_detector() predictor = dlib.shape_predictor('data/data_dlib/shape_predictor_68_face_landmarks.dat') facerec = dlib.face_recognition_model_v1("data/data_dlib/dlib_face_recognition_resnet_model_v1.dat") faces = detector(img_gray, 0) # 若是檢測到人臉 if len(faces) != 0: print(type(faces) # <class 'dlib.dlib.rectangles'> # 遍歷全部檢測到的人臉 for i in range(len(faces)): # 進行人臉比對 shape = predictor(img_rd, faces[i]) print(type(shape)) # <class 'dlib.dlib.full_object_detection'> facerec.compute_face_descriptor(img_rd, shape) print(type(facerec.compute_face_descriptor(img_rd, shape)) # <class 'dlib.dlib.vector'>
這樣一個對象傳遞過程:
faces = detector(img_gray, 0) -> <class 'dlib.dlib.rectangles'> -> shape = predictor(img_rd, faces[i]) -> <class 'dlib.dlib.full_object_detection'> -> facerec.compute_face_descriptor(img_rd, shape) -> <class 'dlib.dlib.vector'>
歐氏距離對比的閾值設定,是在 return_euclidean_distance 函數的 dist 變量;
我這裏程序裏面指定的 歐氏距離判斷閾值是 0.4,具體閾值能夠根據實際狀況或者測得結果進行修改;
這邊作了一個,讓人名跟隨顯示在頭像下方,若是想要在人臉矩形框下方顯示人名,首先須要知道 Dlib 生成的矩形框的尺寸怎麼讀取;
Dlib 返回的 dets 變量是一系列人臉的數據,此處對單張人臉處理,因此取 dets[0] 的參數;
能夠經過 dets[0].top(), dets[0].bottom(), dets[0].left() 和 dets[0].right() 來肯定要顯示的人名的座標;
圖 7 dets[0].top() 等參數說明
獲得矩形框的座標,就能夠獲取人名的相對位置;
這是我這邊取的座標:
pos_text_1 = tuple([dets[0].left(), int(dets[0].bottom()+(dets[0].bottom()-dets[0].top())/4)])
圖 8 face_reco_from_camera.py 生成的人臉識別窗口界面
若是想定製輸出顯示的名字而不是「Person_1」,"Person_2"...;
圖 9 定製顯示名字
1 # 攝像頭實時人臉識別 2 # Real-time face recognition 3 4 # Author: coneypo 5 # Blog: http://www.cnblogs.com/AdaminXie 6 # GitHub: https://github.com/coneypo/Dlib_face_recognition_from_camera 7 8 # Created at 2018-05-11 9 # Updated at 2019-03-23 10 11 import dlib # 人臉處理的庫 Dlib 12 import numpy as np # 數據處理的庫 numpy 13 import cv2 # 圖像處理的庫 OpenCv 14 import pandas as pd # 數據處理的庫 Pandas 15 16 # 人臉識別模型,提取128D的特徵矢量 17 # face recognition model, the object maps human faces into 128D vectors 18 # Refer this tutorial: http://dlib.net/python/index.html#dlib.face_recognition_model_v1 19 facerec = dlib.face_recognition_model_v1("data/data_dlib/dlib_face_recognition_resnet_model_v1.dat") 20 21 22 # 計算兩個128D向量間的歐式距離 23 # compute the e-distance between two 128D features 24 def return_euclidean_distance(feature_1, feature_2): 25 feature_1 = np.array(feature_1) 26 feature_2 = np.array(feature_2) 27 dist = np.sqrt(np.sum(np.square(feature_1 - feature_2))) 28 return dist 29 30 31 # 處理存放全部人臉特徵的 csv 32 path_features_known_csv = "data/features_all.csv" 33 csv_rd = pd.read_csv(path_features_known_csv, header=None) 34 35 # 用來存放全部錄入人臉特徵的數組 36 # the array to save the features of faces in the database 37 features_known_arr = [] 38 39 # 讀取已知人臉數據 40 # print known faces 41 for i in range(csv_rd.shape[0]): 42 features_someone_arr = [] 43 for j in range(0, len(csv_rd.ix[i, :])): 44 features_someone_arr.append(csv_rd.ix[i, :][j]) 45 features_known_arr.append(features_someone_arr) 46 print("Faces in Database:", len(features_known_arr)) 47 48 # Dlib 檢測器和預測器 49 # The detector and predictor will be used 50 detector = dlib.get_frontal_face_detector() 51 predictor = dlib.shape_predictor('data/data_dlib/shape_predictor_68_face_landmarks.dat') 52 53 # 建立 cv2 攝像頭對象 54 # cv2.VideoCapture(0) to use the default camera of PC, 55 # and you can use local video name by use cv2.VideoCapture(filename) 56 cap = cv2.VideoCapture(0) 57 58 # cap.set(propId, value) 59 # 設置視頻參數,propId 設置的視頻參數,value 設置的參數值 60 cap.set(3, 480) 61 62 # cap.isOpened() 返回 true/false 檢查初始化是否成功 63 # when the camera is open 64 while cap.isOpened(): 65 66 flag, img_rd = cap.read() 67 kk = cv2.waitKey(1) 68 69 # 取灰度 70 img_gray = cv2.cvtColor(img_rd, cv2.COLOR_RGB2GRAY) 71 72 # 人臉數 faces 73 faces = detector(img_gray, 0) 74 75 # 待會要寫的字體 font to write later 76 font = cv2.FONT_HERSHEY_COMPLEX 77 78 # 存儲當前攝像頭中捕獲到的全部人臉的座標/名字 79 # the list to save the positions and names of current faces captured 80 pos_namelist = [] 81 name_namelist = [] 82 83 # 按下 q 鍵退出 84 # press 'q' to exit 85 if kk == ord('q'): 86 break 87 else: 88 # 檢測到人臉 when face detected 89 if len(faces) != 0: 90 # 獲取當前捕獲到的圖像的全部人臉的特徵,存儲到 features_cap_arr 91 # get the features captured and save into features_cap_arr 92 features_cap_arr = [] 93 for i in range(len(faces)): 94 shape = predictor(img_rd, faces[i]) 95 features_cap_arr.append(facerec.compute_face_descriptor(img_rd, shape)) 96 97 # 遍歷捕獲到的圖像中全部的人臉 98 # traversal all the faces in the database 99 for k in range(len(faces)): 100 print("##### camera person", k+1, "#####") 101 # 讓人名跟隨在矩形框的下方 102 # 肯定人名的位置座標 103 # 先默認全部人不認識,是 unknown 104 # set the default names of faces with "unknown" 105 name_namelist.append("unknown") 106 107 # 每一個捕獲人臉的名字座標 the positions of faces captured 108 pos_namelist.append(tuple([faces[k].left(), int(faces[k].bottom() + (faces[k].bottom() - faces[k].top())/4)])) 109 110 # 對於某張人臉,遍歷全部存儲的人臉特徵 111 # for every faces detected, compare the faces in the database 112 e_distance_list = [] 113 for i in range(len(features_known_arr)): 114 # 若是 person_X 數據不爲空 115 if str(features_known_arr[i][0]) != '0.0': 116 print("with person", str(i + 1), "the e distance: ", end='') 117 e_distance_tmp = return_euclidean_distance(features_cap_arr[k], features_known_arr[i]) 118 print(e_distance_tmp) 119 e_distance_list.append(e_distance_tmp) 120 else: 121 # 空數據 person_X 122 e_distance_list.append(999999999) 123 # Find the one with minimum e distance 124 similar_person_num = e_distance_list.index(min(e_distance_list)) 125 # print(e_distance_list) 126 # print(similar_person_num) 127 print("Minimum e distance with person", int(similar_person_num)+1) 128 if min(e_distance_list) < 0.4: 129 # 在這裏修改 person_1, person_2 ... 的名字 130 # 能夠在這裏改稱 Jack, Tom and others 131 # Here you can modify the names shown on the camera 132 name_namelist[k] = "Person "+str(int(similar_person_num)+1) 133 print("May be person "+str(int(similar_person_num)+1)) 134 else: 135 print("Unknown person") 136 137 # 矩形框 138 # draw rectangle 139 for kk, d in enumerate(faces): 140 # 繪製矩形框 141 cv2.rectangle(img_rd, tuple([d.left(), d.top()]), tuple([d.right(), d.bottom()]), (0, 255, 255), 2) 142 print('\n') 143 144 # 在人臉框下面寫人臉名字 145 # write names under rectangle 146 for i in range(len(faces)): 147 cv2.putText(img_rd, name_namelist[i], pos_namelist[i], font, 0.8, (0, 255, 255), 1, cv2.LINE_AA) 148 149 print("Faces in camera now:", name_namelist, "\n") 150 151 cv2.putText(img_rd, "Press 'q': Quit", (20, 450), font, 0.8, (84, 255, 159), 1, cv2.LINE_AA) 152 cv2.putText(img_rd, "Face Recognition", (20, 40), font, 1, (0, 0, 0), 1, cv2.LINE_AA) 153 cv2.putText(img_rd, "Faces: " + str(len(faces)), (20, 100), font, 1, (0, 0, 255), 1, cv2.LINE_AA) 154 155 # 窗口顯示 show with opencv 156 cv2.imshow("camera", img_rd) 157 158 # 釋放攝像頭 release camera 159 cap.release() 160 161 # 刪除創建的窗口 delete all the windows 162 cv2.destroyAllWindows()
face_reco_from_camera.py 輸出 log:
##### camera person 1 ##### with person 1 the e distance: 0.21153867687451736 with person 2 the e distance: 0.20646924127167549 with person 4 the e distance: 0.19824469336759548 Minimum e distance with person 4 May be person 4 ##### camera person 2 ##### with person 1 the e distance: 0.7403020289640347 with person 2 the e distance: 0.7375521667680703 with person 4 the e distance: 0.7077921161820342 Minimum e distance with person 4 Unknown person ##### camera person 3 ##### with person 1 the e distance: 0.6975665799095466 with person 2 the e distance: 0.7070867672498581 with person 4 the e distance: 0.6727276688350984 Minimum e distance with person 4 Unknown person Faces in camera now: ['Person 4', 'unknown', 'unknown']
若是對單我的臉,進行實時對比輸出:
圖 10 實時輸出的歐氏距離結果
經過實時的輸出結果,看的比較明顯;
輸出綠色部分:當是我本身時,計算出來的歐式距離基本都在 0.2 左右;
輸出紅色部分:而換一張圖片上去好比特朗普,明顯看到歐式距離計算結果 達到了 0.8,此時就能夠斷定,後來這張人臉不是一張人臉;
因此以前提到的歐式距離計算對比的閾值能夠由此設定,本項目中取的是 dist=0.4;
dist 的確切取值本身權衡,http://dlib.net/face_recognition.py.html 的說明:
# When using a distance threshold of 0.6, the dlib model obtains an accuracy
# of 99.38% on the standard LFW face recognition benchmark, which is # comparable to other state-of-the-art methods for face recognition as of # February 2017. This accuracy means that, when presented with a pair of face # images, the tool will correctly identify if the pair belongs to the same # person or is from different people 99.38% of the time.
3. 總結
核心就是 提取人臉特徵,而後計算歐式距離和預設的特徵臉進行比對;
不過這個實時獲取攝像頭人臉進行比對,要實時的進行計算攝像頭臉的特徵值,而後還要計算歐氏距離,因此計算量比較大,可能攝像頭視頻流會出現卡頓;
此項目僅我的學習愛好研究,開源供你們一塊兒學習;
# 請尊重他人勞動成果,轉載或者使用源碼請註明出處:http://www.cnblogs.com/AdaminXie
# 代碼已上傳到了個人 GitHub,若是對您有幫助歡迎 Star 支持我下:https://github.com/coneypo/Dlib_face_recognition_from_camera
# 若有問題請留言或者聯繫郵箱: coneypo@foxmail.com
# Last update: 6 Apr