使用 dlib 進行人臉識別

語言: CN / TW / HK

theme: hydrogen

「這是我參與2022首次更文挑戰的第32天,活動詳情檢視:2022首次更文挑戰

使用 dlib 進行人臉識別

Dlib 提供了基於深度學習的高效能人臉識別演算法,該模型對戶外資料集中標記人臉的識別準確率可以達到 99.38%。該演算法基於 ResNet-34 網路實現,使用 300 萬張人臉進行訓練,預訓練的模型檔案 dlib_face_recognition_resnet_model_v1.dat 下載後就可以直接用於前向計算。

網路以生成 128 維 (128D) 描述符的方式進行訓練,用於量化人臉。訓練使用三元組執行,單個三元組訓練資料由三個影象組成,其中兩個對應於同一個人。網路為每張影象生成 128D 描述符,三元組損失函式對此進行了量化,嘗試將同一個人的兩個影象的 128D 描述符相距更近,同時將不同人的兩個影象的 128D 描述符相距更遠。

這個過程對數千個不同人的數百萬張影象重複數百萬次,最後,它能夠為每個人生成一個 128D 描述符,最終的 128D 描述符是能夠很好的對人臉進行編碼: - 同一個人的兩幅影象生成的 128D 描述符彼此非常相似 - 不同人的兩張影象生成的 128D 描述符差別很大

因此,利用 dlib 函式,我們可以使用預訓練模型將人臉對映到 128D 描述符。然後使用這些特徵向量來進行人臉識別。

計算 128D 描述符用於量化人臉的過程很簡單: ```python

使用 dlib 庫載入特徵點預測器、人臉編碼和人臉檢測器

pose_predictor_5_point = dlib.shape_predictor("shape_predictor_5_face_landmarks.dat") face_encoder = dlib.face_recognition_model_v1("dlib_face_recognition_resnet_model_v1.dat") detector = dlib.get_frontal_face_detector()

def face_encodings(face_image, number_of_times_to_upsample=1, num_jitters=1): """返回影象中每個人臉的 128D 描述符"""

# 檢測人臉
face_locations = detector(face_image, number_of_times_to_upsample)
# 檢測面部特徵點
raw_landmarks = [pose_predictor_5_point(face_image, face_location) for face_location in face_locations]
# 使用每個檢測到的特徵點計算每個檢測到的人臉的編碼
return [np.array(face_encoder.compute_face_descriptor(face_image, raw_landmark_set, num_jitters)) for
        raw_landmark_set in raw_landmarks]

載入影象並轉換為 RGB 模式

image = cv2.imread("jared_1.jpg") rgb = image[:, :, ::-1]

計算影象中每個人臉的編碼

encodings = face_encodings(rgb)

列印第一個編碼的特徵

print(encodings[0]) 如上所示,關鍵是呼叫 `dlib` 的 `face_encoder.compute_face_descriptor()` 函式,使用檢測到的每個人臉的特徵點計算每個檢測到的人臉的 `128D` 編碼,其中 `num_jitters` 引數用於設定每個人臉隨機抖動的次數,返回值為每次計算的平均 `128D` 描述符,輸出的 `128D` 描述符如下:shell [-0.09235165 0.11607055 0.03648872 -0.08326858 -0.12627071 -0.01334486 -0.11334236 -0.10083835 0.20534235 -0.1636433 0.16874117 -0.05276754 -0.17746128 -0.05377002 -0.02731067 0.24751744 -0.22732623 -0.20258367 -0.03421091 -0.00150665 0.05875423 0.03020219 0.03901095 0.03496565 -0.15658092 -0.34250638 -0.08725534 -0.06245319 -0.04688681 -0.04861078 -0.07620423 0.05013577 -0.18563135 -0.04075277 0.05248301 0.09195475 -0.00887688 -0.1192601 0.18633801 0.00056917 -0.29226956 0.01442468 0.09583923 0.19053322 0.15580602 -0.04580544 0.01866002 -0.15243134 0.13535264 -0.17270051 0.03029358 0.16308595 0.04719323 0.08862312 0.01600051 -0.112983 0.06787978 0.17171389 -0.09536573 -0.02140218 0.11402114 -0.04710582 -0.01966342 -0.0705786 0.21773803 0.12153016 -0.08498291 -0.24783675 0.06667361 -0.08091511 -0.11054871 0.08837797 -0.17216064 -0.18642734 -0.27270097 -0.03300989 0.31748736 0.06824204 -0.16750985 0.0599058 -0.00497202 -0.02882685 0.07890167 0.19422579 -0.02771271 0.05871597 -0.06130363 0.04929798 0.27234387 -0.04948008 -0.00844343 0.22556995 0.00912007 0.07115038 0.01273906 0.03535268 -0.05074561 0.05441948 -0.13103089 -0.00421767 0.07432865 0.0025964 -0.06208063 0.12578207 -0.16597968 0.09258381 -0.02716768 0.02978029 -0.00216489 -0.01805471 -0.04702468 -0.05231683 0.11994087 -0.16787212 0.17464222 0.16930985 0.05848085 0.09450675 0.11558257 0.0659898 -0.00265438 -0.01509937 -0.22738113 0.01624682 0.13056616 -0.04214386 0.06433617 0.00774699] ``` 獲取到檢測到的人臉編碼後,下一步就是進行人臉識別。

使用 128D 描述符計算的某種距離度量可以用於執行人臉識別,如果兩個人臉描述符向量之間的歐幾里得距離小於 0.6 (歐幾里得距離可以使用 numpy.linalg.norm() 計算),則可以認為它們屬於同一個人;否則,他們是不同的人。

接下來,我們使用 5 張已知影象與另 1 張測試影象進行比較。為了比較人臉,我們需要編寫兩個函式:compare_faces()compare_faces_ordered()

compare_faces() 函式返回已知人臉編碼與待識別人臉間的距離: python def compare_faces(encodings, encoding_to_check): return list(np.linalg.norm(encodings - encoding_to_check, axis=1)) compare_faces_ordered() 函式返回排序後的已知人臉編碼與待識別人臉間的距離和相應的名稱: python def compare_faces_ordered(encodings, face_names, encoding_to_check): distances = list(np.linalg.norm(encodings - encoding_to_check, axis=1)) return zip(*sorted(zip(distances, face_names))) 接下來,將 5 個已標記影象與 1 個未標記影象進行比較,第一步是載入所有影象並轉換為 RGB 格式: ```python

載入所有影象並轉換為 RGB 格式

known_image_1 = cv2.imread("小新_1.png") known_image_2 = cv2.imread("小甜_1.png") known_image_3 = cv2.imread("小甜_2.png") known_image_4 = cv2.imread("小甜_3.png") known_image_5 = cv2.imread("小新_2.png") unknown_image = cv2.imread("test.png") known_image_1 = known_image_1[:, :, ::-1] known_image_2 = known_image_2[:, :, ::-1] known_image_3 = known_image_3[:, :, ::-1] known_image_4 = known_image_4[:, :, ::-1] known_image_5 = known_image_5[:, :, ::-1] unknown_image = unknown_image[:, :, ::-1]

標記人臉

names = ["小新_1.png", "小甜_1.png", "小甜_2.png", "小甜_3.png", "小新_2.png"] 下一步是計算每個影象的 `128D` 編碼:python

計算每個影象的 128D 編碼

known_image_1_encoding = face_encodings(known_image_1)[0] known_image_2_encoding = face_encodings(known_image_2)[0] known_image_3_encoding = face_encodings(known_image_3)[0] known_image_4_encoding = face_encodings(known_image_4)[0] known_image_5_encoding = face_encodings(known_image_5)[0] known_encodings = [known_image_1_encoding, known_image_2_encoding, known_image_3_encoding, known_image_4_encoding, known_image_5_encoding] unknown_encoding = face_encodings(unknown_image)[0] 最後,可以使用 `compare_faces_ordered()` 函式比較與識別人臉:python computed_distances_ordered, ordered_names = compare_faces_ordered(known_encodings, names, unknown_encoding)

列印返回資訊

print(computed_distances) print(computed_distances_ordered) print(ordered_names) 列印的返回資訊如下: (0.26459402873041915, 0.2728113455078627, 0.2945116087102425, 0.42567525558949304, 0.42899966791571725) ('小甜', '小甜', '小甜', '小新', '小新') ``` 通過上示的列印資訊,可以得出結論待識別的人臉屬於小甜,而小新的人臉編碼資訊與待識別人臉的編碼資訊距離較遠,表示不是同一個人:

使用 dlib 進行人臉識別