Python 3 利用 Dlib 實現攝像頭實時人臉識別

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 :

  • 支持人臉數據採集,自行創建人臉數據庫 / Support face register
  • 調用攝像頭實時人臉檢測和識別 / Using camera to real-time detect and recognize faces
  • 支持多張人臉 / Support multi-faces

 

人臉識別 / 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.源碼介紹

主要有

  • get_faces_from_camera.py 
  • features_extraction_to_csv.py
  • face_reco_from_camera.py

這三個 Python 文件,接下來會分別介紹實現功能;

 

2.1 get_faces_from_camera.py / 人臉註冊錄入

人臉識別須要將 提取到的圖像數據 和 已有圖像數據 進行比對分析,因此這部分代碼實現的功能就是 人臉錄入

程序會生成一個窗口,顯示調用的攝像頭實時獲取的圖像;

(關於攝像頭的調用方式能夠參考這裏: Python 3 利用 Dlib 19.7 實現攝像頭人臉檢測特徵點標定);

  

而後根據鍵盤輸入進行人臉捕獲:

  • 「N」 新錄入人臉,新建文件夾 person_X/  用來存儲某人的人臉圖像
  •   "S" 開始捕獲人臉,將捕獲到的人臉放到 person_X/ 路徑下
  • 「Q」 退出窗口

  

攝像頭的調用是利用 opencv 庫的 cv2.VideoCapture(0), 此處參數爲 0 表明調用的是筆記本的默認攝像頭,你也可讓它調用傳入已有視頻文件;

 

圖 3  get_face_from_camera.py 的界面

   

捕獲到的一組人臉示例;

圖 4 捕獲到的一組人臉

 

get_faces_from_camera.py 源碼:

  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 定製顯示名字

 

face_reco_from_camera.py 源碼:

 

  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

相關文章
相關標籤/搜索