一、背景介紹
計(jì)算機(jī)視覺(jué)技術(shù)在當(dāng)前人工智能發(fā)展進(jìn)程中已然達(dá)到較高成熟度,一系列基礎(chǔ)算法與應(yīng)用場(chǎng)景獲得廣泛實(shí)踐與驗(yàn)證。在算法層面,圖像處理、目標(biāo)檢測(cè)、語(yǔ)義分割等多個(gè)領(lǐng)域的技術(shù)不斷突破,準(zhǔn)確率與效率持續(xù)提升。在應(yīng)用上,人臉識(shí)別、車牌識(shí)別、醫(yī)學(xué)圖像分析等已步入商業(yè)化應(yīng)用階段,被廣泛應(yīng)用于安防監(jiān)控、智能駕駛、醫(yī)療輔助診斷等領(lǐng)域,大幅提升效率并創(chuàng)造新的應(yīng)用形式。
基于此,結(jié)合公司規(guī)劃與業(yè)務(wù)需求,我們決定在人臉識(shí)別領(lǐng)域進(jìn)行自主研發(fā)與應(yīng)用。具體來(lái)看,公司主要面臨以下應(yīng)用需求:
-
業(yè)務(wù)背景:主要應(yīng)用于一些智能終端設(shè)備上,在進(jìn)行權(quán)限驗(yàn)證和流程控制上需要進(jìn)行人臉識(shí)別驗(yàn)證
-
平臺(tái)架構(gòu):平臺(tái)整體架構(gòu)以云+端的模式,一個(gè)云平臺(tái)部署在地市或者省廳,下屬分局和派出所等場(chǎng)所部署N個(gè)終端設(shè)備,每臺(tái)設(shè)備配置雙目攝像頭,連接云端平臺(tái),實(shí)現(xiàn)人臉相關(guān)功能。
-
部署架構(gòu):平臺(tái)主要部署在地市和省廳,平臺(tái)系統(tǒng)整體并發(fā)量并不算特別高,一般地市也就在20 ~ 30 QPS。但需要部署在專網(wǎng),所以人臉?lè)?wù)需可做本地私有化部署,無(wú)法使用SaaS服務(wù)。
-
功能需求:軟件平臺(tái)包括人臉庫(kù)的管理,和人臉數(shù)據(jù)采集。終端設(shè)備主要包括人臉識(shí)別、人臉比對(duì)(1:1和1:N)、活體檢測(cè)。
-
人臉底庫(kù):根據(jù)實(shí)際部署需求,底庫(kù)從萬(wàn)級(jí)到千萬(wàn)級(jí)不等。具體根據(jù)項(xiàng)目規(guī)模來(lái)。
通過(guò)自主研發(fā),我們不僅能充分考量業(yè)務(wù)場(chǎng)景的特點(diǎn),實(shí)現(xiàn)針對(duì)性的技術(shù)創(chuàng)新與效率優(yōu)化,也能隨時(shí)針對(duì)算法與模型進(jìn)行調(diào)整升級(jí),為公司整體技術(shù)實(shí)力與核心競(jìng)爭(zhēng)力的提升奠定堅(jiān)實(shí)基礎(chǔ)。
本文將介紹如何使用 Dlib 庫(kù)和深度學(xué)習(xí)來(lái)實(shí)現(xiàn)人臉識(shí)別,如何利用預(yù)訓(xùn)練網(wǎng)絡(luò)和OpenCV庫(kù)進(jìn)行圖像處理。OpenCV 庫(kù)將用于執(zhí)行一些簡(jiǎn)單的圖像處理任務(wù),例如將圖像轉(zhuǎn)換為灰度、調(diào)整圖像大小等,從而輕松地在各種場(chǎng)景中應(yīng)用人臉識(shí)別技術(shù)。
我們將使用 Dlib 提供的預(yù)訓(xùn)練網(wǎng)絡(luò)。該網(wǎng)絡(luò)已在超過(guò) 300 萬(wàn)張圖像的數(shù)據(jù)集上進(jìn)行了訓(xùn)練。該網(wǎng)絡(luò)稱為 ResNet-34。
二、人臉識(shí)別概述
人臉識(shí)別是一種通過(guò)分析個(gè)人面部特征來(lái)識(shí)別或驗(yàn)證身份的技術(shù)。它在驗(yàn)證個(gè)人身份、尋找失蹤人員、識(shí)別罪犯等方面發(fā)揮著重要作用。該技術(shù)利用已知人臉的數(shù)據(jù)庫(kù),將其與未知人臉進(jìn)行比較,以找到匹配并預(yù)測(cè)其身份。
為了實(shí)現(xiàn)這一目標(biāo),人臉識(shí)別采用了多種算法,包括特征臉、局部二進(jìn)制模式和深度學(xué)習(xí)等。本文將深入探討如何運(yùn)用深度學(xué)習(xí)方法來(lái)進(jìn)行人臉識(shí)別,以提高準(zhǔn)確性和效率。通過(guò)學(xué)習(xí)這些技術(shù),您將能夠更好地理解人臉識(shí)別的原理和應(yīng)用,并在實(shí)際場(chǎng)景中應(yīng)用它們。無(wú)論是保障安全、提升便捷性還是推動(dòng)科技創(chuàng)新,人臉識(shí)別都具有廣闊的前景和潛力。
三、人臉識(shí)別步驟
人臉識(shí)別一般分為以下4步:
-
人臉檢測(cè):人臉識(shí)別流程的第一步是檢測(cè)圖像中的所有人臉。通過(guò)使用不同的人臉檢測(cè)器(如Haar級(jí)聯(lián)、HOG或基于深度學(xué)習(xí)的檢測(cè)器),我們可以檢測(cè)圖像中的人臉。本文我們將使用 Dlib 提供的 HOG 人臉檢測(cè)器實(shí)現(xiàn)。
-
面部對(duì)齊(可選):使用面部標(biāo)志來(lái)對(duì)齊或標(biāo)準(zhǔn)化面部,以提高識(shí)別系統(tǒng)的準(zhǔn)確性。本文將跳過(guò)此步驟。
-
面部編碼:將面部圖像傳遞給模型,并提取面部特征。
-
人臉識(shí)別:將提取的人臉特征與已知人臉特征的數(shù)據(jù)庫(kù)進(jìn)行比較,嘗試找到匹配。常用的算法包括K最近鄰(KNN)、支持向量機(jī)(SVM)和隨機(jī)森林等。
四、人臉識(shí)別算法及基本原理?
基于深度學(xué)習(xí)的人臉識(shí)別算法是建立在卷積神經(jīng)網(wǎng)絡(luò)(CNN)的基礎(chǔ)上的。這些算法中的一種被稱為孿生網(wǎng)絡(luò),它由兩個(gè)或多個(gè)相同的子網(wǎng)絡(luò)組成。每個(gè)子網(wǎng)絡(luò)共享相同的權(quán)重和參數(shù)。這種架構(gòu)使得模型能夠比較輸入圖像并找到它們之間的相似性,這對(duì)于人臉識(shí)別非常重要。
?目前,有許多先進(jìn)的孿生網(wǎng)絡(luò)架構(gòu)被用于人臉識(shí)別,其中一些包括:
-
VGG-Face
:基于VGGNet的人臉識(shí)別模型,具有較高的準(zhǔn)確性和魯棒性。 -
Dlib
的基于ResNet的人臉識(shí)別模型:使用ResNet架構(gòu),該模型在人臉識(shí)別領(lǐng)域表現(xiàn)出色。 -
FaceNet
:通過(guò)將人臉圖像映射到高維空間中的特征向量來(lái)實(shí)現(xiàn)人臉識(shí)別。 -
OpenFace
:采用深度神經(jīng)網(wǎng)絡(luò)進(jìn)行人臉識(shí)別,具有較高的準(zhǔn)確性和魯棒性。 -
Facebook DeepFace
:Facebook開(kāi)發(fā)的人臉識(shí)別系統(tǒng),利用深度學(xué)習(xí)技術(shù)實(shí)現(xiàn)高精度的人臉識(shí)別。 -
DeepID
:通過(guò)多層神經(jīng)網(wǎng)絡(luò)學(xué)習(xí)人臉特征,實(shí)現(xiàn)準(zhǔn)確的人臉識(shí)別。 -
ArcFace
:采用角度余弦損失函數(shù)來(lái)提高人臉識(shí)別的準(zhǔn)確性。 -
SFace
:結(jié)合了判別性特征學(xué)習(xí)和度量學(xué)習(xí)的人臉識(shí)別算法,具有較高的魯棒性和準(zhǔn)確性。
在本文中,我們將使用Dlib基于ResNet-34架構(gòu)的人臉識(shí)別模型。該模型通過(guò)深度學(xué)習(xí)技術(shù)實(shí)現(xiàn)了對(duì)人臉的準(zhǔn)確識(shí)別,并在實(shí)際應(yīng)用中取得了良好的效果。通過(guò)研究和理解這些基于深度學(xué)習(xí)的人臉識(shí)別算法及其工作原理,我們可以更好地應(yīng)用它們于實(shí)際場(chǎng)景,并推動(dòng)人臉識(shí)別技術(shù)的發(fā)展和創(chuàng)新。
在網(wǎng)絡(luò)訓(xùn)練過(guò)程中,該模型使用了三個(gè)圖像進(jìn)行輸入:
-
"錨點(diǎn)"圖像:這是給定的人物圖像,作為訓(xùn)練的基準(zhǔn)。
-
"正樣本"圖像:這是與錨點(diǎn)圖像相同人物的圖像,用于訓(xùn)練網(wǎng)絡(luò)識(shí)別相似人物。
-
"負(fù)樣本"圖像:這是不同人物的圖像,用于訓(xùn)練網(wǎng)絡(luò)區(qū)分不同人物。
通過(guò)將這三個(gè)圖像輸入到網(wǎng)絡(luò)中,網(wǎng)絡(luò)會(huì)為每個(gè)圖像生成一個(gè)128維的嵌入向量。
在訓(xùn)練過(guò)程中,神經(jīng)網(wǎng)絡(luò)使用損失函數(shù)來(lái)衡量嵌入向量之間的距離。如果相似人物的嵌入向量(即錨點(diǎn)和正樣本圖像)之間的距離較大,或者兩個(gè)不同人物的嵌入向量(即錨點(diǎn)和負(fù)樣本圖像)之間的距離較小,則網(wǎng)絡(luò)會(huì)受到懲罰。
通過(guò)這種訓(xùn)練方式,網(wǎng)絡(luò)逐漸學(xué)習(xí)生成更接近的嵌入向量來(lái)表示相同人物的圖像,同時(shí)將不同人物的圖像生成更遠(yuǎn)離的嵌入向量。這樣,網(wǎng)絡(luò)就能夠通過(guò)嵌入向量的距離來(lái)判斷圖像之間的相似性,從而實(shí)現(xiàn)準(zhǔn)確的人臉識(shí)別。通過(guò)不斷優(yōu)化網(wǎng)絡(luò)的訓(xùn)練過(guò)程,可以提高人臉識(shí)別算法的準(zhǔn)確性和魯棒性,使其在實(shí)際應(yīng)用中更加可靠和有效。

一旦網(wǎng)絡(luò)訓(xùn)練完成,我們可以利用它為新圖像生成嵌入向量。這些嵌入向量可用于訓(xùn)練人臉識(shí)別分類器,而分類器可以采用各種機(jī)器學(xué)習(xí)算法,如K最近鄰(KNN)、支持向量機(jī)(SVM)和隨機(jī)森林等。在本文中,我們將使用K最近鄰算法。
然而,需要說(shuō)明的是,我們并不需要從頭開(kāi)始訓(xùn)練模型,因?yàn)槲覀兛梢允褂靡粋€(gè)預(yù)訓(xùn)練好的模型。因此,我們的任務(wù)是獲取這個(gè)預(yù)訓(xùn)練好的模型,并利用它為我們自己的數(shù)據(jù)集生成特征(也稱為嵌入向量)。接著,我們將這些特征存儲(chǔ)在數(shù)據(jù)庫(kù)或文件中。
當(dāng)我們獲得一張新的圖像時(shí),我們會(huì)檢測(cè)圖像中的人臉,并從圖像中提取出人臉區(qū)域,然后將其輸入到模型中。模型會(huì)生成一個(gè)128維的嵌入向量。
最后,我們使用K最近鄰算法計(jì)算這個(gè)新人臉嵌入向量與我們數(shù)據(jù)庫(kù)中所有人臉嵌入向量之間的距離。距離最接近的人就是新圖像中的人。
通過(guò)這樣的流程,我們能夠快速準(zhǔn)確地識(shí)別人臉,實(shí)現(xiàn)高效的人臉識(shí)別應(yīng)用。這種基于深度學(xué)習(xí)的人臉識(shí)別算法在安全領(lǐng)域、人臉支付、人臉門禁等多個(gè)領(lǐng)域具有廣泛的應(yīng)用前景。
五、人臉識(shí)別服務(wù)開(kāi)發(fā)
5.1、安裝必要依賴庫(kù)
為了實(shí)現(xiàn)人臉識(shí)別功能,我們需要安裝一些必要的依賴庫(kù),包括OpenCV
、Dlib
和Numpy
(在安裝之前,請(qǐng)確保已經(jīng)安裝了CMake
)。
這些庫(kù)都可以通過(guò)使用pip命令來(lái)進(jìn)行安裝。
首先,我們需要?jiǎng)?chuàng)建一個(gè)虛擬環(huán)境。然后,激活該虛擬環(huán)境,并使用pip命令來(lái)安裝所需的庫(kù)。
$ python3 -m venv venv
$ source venv/bin/activate
$ pip install -r requirements.txt
5.2、準(zhǔn)備人臉數(shù)據(jù)集
本文將使用Labeled Faces in the Wild (LFW)數(shù)據(jù)集進(jìn)行人臉識(shí)別任務(wù)。該數(shù)據(jù)集包含了超過(guò)13,000張從網(wǎng)絡(luò)上收集的面部圖像。
這個(gè)數(shù)據(jù)集被分成了5749個(gè)目錄,每個(gè)目錄中包含了一個(gè)人的1到530張圖像。因此,整個(gè)數(shù)據(jù)集中包含了5749個(gè)不同的人。
要下載這個(gè)數(shù)據(jù)集,您可以前往LFW數(shù)據(jù)集網(wǎng)站并點(diǎn)擊"Download
"按鈕。
然后單擊All images as gzipped tar file
鏈接進(jìn)行下載,下載完成后。會(huì)得到一個(gè)名為lfw.tgz
的壓縮文件。
解壓縮lfw.tgz
文件后,您將獲得數(shù)據(jù)集中的所有圖像。在本文中,我們將僅選擇4個(gè)不同的人來(lái)執(zhí)行人臉識(shí)別任務(wù)。我選擇的人物是:阿諾·施瓦辛格、讓·克雷蒂安、小泉純一郎和雷杰普·塔伊普·埃爾多安。
?同時(shí),我們還刪除了那些包含多張面孔的圖像,因?yàn)槲覀兊乃惴僭O(shè)每張圖像中只有一個(gè)或多個(gè)屬于同一個(gè)人的面孔。
5.3、項(xiàng)目整體結(jié)構(gòu)
本教程的項(xiàng)目結(jié)構(gòu)如下:
tree --filelimit 10 --dirsfirst
├── dataset
│ ├── Arnold_Schwarzenegger [35 entries]
│ ├── Jean_Chretien [48 entries]
│ ├── Junichiro_Koizumi [47 entries]
│ └── Recep_Tayyip_Erdogan [24 entries]
├── examples [14 entries]
├── models
│ ├── dlib_face_recognition_resnet_model_v1.dat
│ └── shape_predictor_68_face_landmarks.dat
├── venv
├── encodings.pickle
├── face_encoding.py
├── face_recognition_images.py
├── face_recognition_videos.py
├── requirements.txt
└── utils.py
以下是每個(gè)目錄/文件的簡(jiǎn)要說(shuō)明:
-
dataset/
:包含我們想要識(shí)別的人的圖像。 -
example/
:包含一些示例圖像,我們將使用它們來(lái)測(cè)試我們的人臉識(shí)別系統(tǒng)。 -
models/
:包含我們將用于生成人臉嵌入的預(yù)訓(xùn)練模型。 -
venv/
:我們的虛擬環(huán)境。 -
codings.pickle
:包含我們數(shù)據(jù)集中的人臉嵌入的文件。這些嵌入將由face_encoding.py腳本生成。 -
face_encoding.py
:此文件包含用于生成數(shù)據(jù)集中的人臉嵌入的代碼。 -
face_recognition_images.py
:該文件包含用于對(duì)圖像執(zhí)行人臉識(shí)別的代碼。 -
face_recognition_videos.py
:此文件包含對(duì)視頻執(zhí)行人臉識(shí)別的代碼。 -
requirements.txt
:包含我們需要安裝的庫(kù)的列表。您可以使用命令pip install -rrequirements.txt安裝它們。 -
utils.py
:為了使我們的代碼更有條理,我們將把所有實(shí)用函數(shù)放在這個(gè)文件中。
5.4、提取人臉特征
在進(jìn)行人臉識(shí)別之前,我們首先需要加載待識(shí)別人物的圖像。然后,我們將從這些圖像中提取出面部區(qū)域,并為每個(gè)面部區(qū)域生成相應(yīng)的面部嵌入。接下來(lái),讓我們導(dǎo)入所需的包和模型。請(qǐng)打開(kāi)utils.py
文件,并編寫以下代碼:
import dlib
from glob import glob
import cv2
import numpy as np
import os
# 加載人臉檢測(cè)器、關(guān)鍵點(diǎn)預(yù)測(cè)器和人臉識(shí)別模型
face_detector = dlib.get_frontal_face_detector()
shape_predictor = dlib.shape_predictor("models/shape_predictor_68_face_landmarks.dat")
face_encoder = dlib.face_recognition_model_v1("models/dlib_face_recognition_resnet_model_v1.dat")
人臉檢測(cè)器(face_ detector
)用于檢測(cè)輸入圖像中的人臉區(qū)域。
地標(biāo)預(yù)測(cè)器 ( ***shape_predictor***
) 用于定位面部區(qū)域中的面部地標(biāo)。我們需要面部標(biāo)志來(lái)生成面部嵌入。
人臉編碼器模型(face_encoder
)用于生成人臉嵌入。
接下來(lái),我們將獲取數(shù)據(jù)集中圖像的路徑。讓我們?yōu)榇藙?chuàng)建一個(gè)輔助函數(shù):
# 更改此處以包括您想要支持的其他圖像格式(例如.bmp)
VALID_EXTENSIONS = ['.png', '.jpg', '.jpeg']
def get_image_paths(root_dir, class_names):
""" 獲取數(shù)據(jù)集中圖像的路徑"""
image_paths = []
get_image_paths **()
函數(shù)有兩個(gè)參數(shù):root_dir
和class_names
。rootdir是數(shù)據(jù)集的路徑。classnames是我們想要識(shí)別的每個(gè)人的姓名列表。class_names**列表如下所示:
>>> class_names
[‘Huangjiaju’, 'Zhangguorong', 'Recep_Tayyip_Erdogan', 'Jean_Chretien', 'Junichiro_Koizumi', 'Arnold_Schwarzenegger']
現(xiàn)在,我們將循環(huán)遍歷類名,對(duì)于每個(gè)類名,我們將循環(huán)遍歷目錄中的圖像,并將圖像的路徑添加到 image_paths
列表中。
# 循環(huán)遍歷類名
for class_name in class_names:
# 獲取當(dāng)前類目錄中文件的路徑
class_dir = os.path.sep.join([root_dir, class_name])
class_file_paths = glob(os.path.sep.join([class_dir, '*.*']))
# 循環(huán)遍歷當(dāng)前類目錄中的文件路徑
for file_path in class_file_paths:
# 提取當(dāng)前文件的文件擴(kuò)展名
ext = os.path.splitext(file_path)[1]
# 如果文件擴(kuò)展名不在有效擴(kuò)展名列表中,則忽略該文件
if ext.lower() not in VALID_EXTENSIONS:
print("Skipping file: {}".format(file_path))
continue
# 將當(dāng)前圖像的路徑添加到圖像路徑列表中
image_paths.append(file_path)
return image_paths
glob **()
**函數(shù)返回當(dāng)前類目錄中文件的路徑列表。我們循環(huán)遍歷文件路徑并提取當(dāng)前文件的文件擴(kuò)展名。如果文件擴(kuò)展名無(wú)效(不是圖像),我們將跳過(guò)它并繼續(xù)下一個(gè)。
如果文件擴(kuò)展名有效(圖像),我們將當(dāng)前圖像的路徑添加到image_paths
列表中。讓我們測(cè)試一下get_image_paths()
函數(shù)。
>>> from utils import get_image_paths
>>> class_names = ['Recep_Tayyip_Erdogan', 'Jean_Chretien', 'Junichiro_Koizumi', 'Arnold_Schwarzenegger']
>>> image_paths = get_image_paths("dataset", class_names)
>>> image_paths
['dataset/Recep_Tayyip_Erdogan/Recep_Tayyip_Erdogan_0017.jpg', 'dataset/Recep_Tayyip_Erdogan/Recep_Tayyip_Erdogan_0013.jpg', 'dataset/Recep_Tayyip_Erdogan/Recep_Tayyip_Erdogan_0012.jpg', ...]
如您所見(jiàn),get_image_paths()
函數(shù)返回?cái)?shù)據(jù)集中圖像的路徑列表。接下來(lái),我們將創(chuàng)建一個(gè)輔助函數(shù)來(lái)從圖像中提取面部區(qū)域。為此,我們將使用 Dlib 人臉檢測(cè)器。
def face_rects(image):
# 將圖像轉(zhuǎn)換為灰度圖像
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 在灰度圖像中檢測(cè)人臉
rects = face_detector(gray, 1)
# 返回邊界框
return rects
face_rects **()
**函數(shù)將圖像作為輸入并將我們的面部檢測(cè)器應(yīng)用于它。它返回圖像中面部區(qū)域的邊界框?,F(xiàn)在我們有了邊界框,我們可以使用它們來(lái)應(yīng)用地標(biāo)預(yù)測(cè)器并獲取面部地標(biāo)。
def face_landmarks(image):
return [shape_predictor(image, face_rect) for face_rect in face_rects(image)]
該函數(shù)循環(huán)遍歷每個(gè)面部區(qū)域的邊界框。對(duì)于每個(gè)面部區(qū)域,它應(yīng)用地標(biāo)預(yù)測(cè)器。它返回一個(gè)包含每個(gè)面部區(qū)域的面部標(biāo)志的列表?,F(xiàn)在,最后一步是為每個(gè)面部區(qū)域生成面部嵌入。同樣,我們將為此創(chuàng)建一個(gè)輔助函數(shù)。
def face_encodings(image):
# 計(jì)算每個(gè)人臉的面部嵌入。`compute_face_descriptor`函數(shù)返回一個(gè)描述圖像中人臉的128維向量
return [np.array(face_encoder.compute_face_descriptor(image, face_landmark))
for face_landmark in face_landmarks(image)]
因此,這里的face_encodings()
函數(shù)將圖像作為輸入并循環(huán)遍歷每個(gè)面部區(qū)域的面部標(biāo)志。對(duì)于每個(gè)面部區(qū)域,它應(yīng)用面部編碼器并生成面部嵌入。它返回一個(gè)包含每個(gè)面部區(qū)域的面部嵌入的列表。讓我們測(cè)試一下我們的face_encodings()
函數(shù)。
>>> from utils import face_encodings
>>> import cv2
>>> image = cv2.imread("dataset/Recep_Tayyip_Erdogan/Recep_Tayyip_Erdogan_0017.jpg")
>>> face_encodings(image)
[array([-0.06507568, 0.09282234, -0.05310396, 0.02033956, -0.05189228,
0.0038331 , 0.02058978, -0.16266678, 0.16215618, -0.07854272,
0.22294444, -0.02746225, -0.21170133, -0.10646843, 0.12207212,
0.08830512, -0.1529105 , -0.15543598, -0.13133761, -0.07789465,
-0.01266594, -0.03342287, -0.07684287, -0.01465143, -0.16457887,
-0.29837033, -0.07858203, -0.06912123, 0.10793255, -0.06668072,
0.05952527, -0.01771747, -0.18992454, -0.10981462, 0.09109481,
0.06847958, -0.06725877, -0.02276845, 0.15260877, -0.05116167,
-0.13816157, -0.05038669, 0.10000665, 0.25293767, 0.11579101,
0.09511411, 0.05221565, -0.10308918, ...])]
>>> face_encodings(image)[0].shape
(128,)
如您所見(jiàn),face_encodings()
函數(shù)返回一個(gè)列表,其中包含圖像中每個(gè)人臉區(qū)域的人臉嵌入。每個(gè)人臉嵌入都是一個(gè) 128 維的 Numpy 數(shù)組。
我們將從數(shù)據(jù)集中的每個(gè)圖像生成人臉嵌入開(kāi)始。然后我們將面部嵌入存儲(chǔ)在字典中。字典的鍵將是數(shù)據(jù)集中每個(gè)人的姓名,值將是該人的每個(gè)圖像的面部嵌入列表。
最后,我們將字典保存到磁盤。打開(kāi)face_encoding.py
文件并添加以下代碼:
import pickle
import cv2
import os
from utils import get_image_paths
from utils import face_encodings
root_dir = "dataset"
class_names = os.listdir(root_dir)
# 獲取圖像的路徑
image_paths = get_image_paths(root_dir, class_names)
# 初始化一個(gè)字典來(lái)存儲(chǔ)每個(gè)人的姓名和相應(yīng)的編碼
name_encondings_dict = {}
我們將使用pickle模塊將字典保存到文件中,以便稍后在測(cè)試人臉識(shí)別系統(tǒng)時(shí)使用它。這里我們使用get_image_paths()
函數(shù)來(lái)獲取數(shù)據(jù)集中圖像的路徑。我們還初始化一個(gè)字典來(lái)存儲(chǔ)標(biāo)簽(每個(gè)人的名字)和相應(yīng)的面部嵌入?,F(xiàn)在,我們將循環(huán)圖像的路徑并為每個(gè)圖像生成面部嵌入。
# 初始化處理的圖像數(shù)量
nb_current_image = 1
# 現(xiàn)在我們可以循環(huán)遍歷圖像路徑,定位人臉并對(duì)其進(jìn)行編碼
for image_path in image_paths:
print(f"Image processed {nb_current_image}/{len(image_paths)}")
# 加載圖像
image = cv2.imread(image_path)
# 獲取人臉嵌入
encodings = face_encodings(image)
# 從圖像路徑中獲取姓名
name = image_path.split(os.path.sep)[-2]
# 獲取當(dāng)前姓名的編碼
e = name_encondings_dict.get(name, [])
# 更新當(dāng)前姓名的編碼列表
e.extend(encodings)
# 更新當(dāng)前姓名的編碼列表
name_encondings_dict[name] = e
nb_current_image += 1
所以這里我們循環(huán)遍歷圖像的路徑。對(duì)于每條路徑,我們使用 OpenCV 加載圖像并使用face_encodings()
函數(shù)生成人臉嵌入。
回想一下,在內(nèi)部,face_encodings()
函數(shù)應(yīng)用面部檢測(cè)器來(lái)獲取圖像中面部區(qū)域的邊界框,然后應(yīng)用標(biāo)志預(yù)測(cè)器來(lái)獲取面部標(biāo)志。最后,它使用面部標(biāo)志應(yīng)用面部編碼器來(lái)生成面部嵌入。
我們還從圖像的路徑中獲取人名。圖像路徑的格式為 dataset /RecepTayyipErdogan/RecepTayyipErdogan_0017.jpg。因此,我們可以通過(guò)使用目錄分隔符 ( os.path.sep
)分割路徑并獲取列表的倒數(shù)第二個(gè)元素來(lái)獲取人員的姓名。
接下來(lái),我們嘗試從字典中獲取當(dāng)前人的面部嵌入列表。如果字典中沒(méi)有這個(gè)人的名字,我們會(huì)為面部嵌入初始化一個(gè)空列表。
然后,我們使用為當(dāng)前圖像生成的人臉嵌入來(lái)擴(kuò)展嵌入列表。最后,我們使用當(dāng)前人的新面部嵌入列表更新字典。
循環(huán)之后,我們將擁有一個(gè)字典,其中包含每個(gè)人的姓名以及該人的每個(gè)圖像的相應(yīng)面部嵌入列表。
字典看起來(lái)像這樣:
>>> name_encondings_dict
{'Recep_Tayyip_Erdogan': [array([-0.05895536, 0.07766615, ...]),
array([-0.04809677, 0.08508434, ...]),
...],
'Jean_Chretien': [array([-0.18319653, -0.18853943, ...]),
array([-0.065067637, 0.13090725, ...]),
...],
'Junichiro_Koizumi': [array([-0.18313943, 0.07619441, ...]),
array([-0.18313943, 0.0761441, ...]),
...],
'Arnold_Schwarzenegger': [array([-0.117762501, 0.152411991, ...]),
array([-0.117625501, 0.152341991, ...]),
...],
}
最后一步是使用pickle
模塊將字典保存到文件中。
# 將名稱編碼字典保存到磁盤
with open("encodings.pickle", "wb") as f:
pickle.dump(name_encondings_dict, f)
現(xiàn)在,我們可以運(yùn)行face_encoding.py
腳本來(lái)為數(shù)據(jù)集中的每個(gè)圖像生成人臉嵌入。打開(kāi)終端,導(dǎo)航到項(xiàng)目目錄,然后運(yùn)行以下命令:
$ python face_encoding.py
Image processed 1/162
Image processed 2/162
Image processed 3/162
...
Image processed 160/162
Image processed 161/162
Image processed 162/162
腳本運(yùn)行完成后,您應(yīng)該在項(xiàng)目目錄中看到一個(gè)名為encodings.pickle
的文件。該文件包含帶有每個(gè)人的姓名的字典以及該人的每個(gè)圖像的相應(yīng)面部嵌入列表。
5.5、人臉識(shí)別比對(duì)
現(xiàn)在我們有了面部嵌入,我們可以開(kāi)始識(shí)別圖像中的面部。我們將在face_recognition_images.py
文件中編寫以下代碼:
import pickle
import cv2
from utils import face_rects
from utils import face_encodings
# 加載編碼 + 名稱字典
with open("encodings.pickle", "rb") as f:
name_encodings_dict = pickle.load(f)
# 加載輸入圖像
image = cv2.imread("examples/18.jpeg")
# 為輸入圖像中的每個(gè)人臉獲取128維面部嵌入
encodings = face_encodings(image)
# 此列表將包含圖像中檢測(cè)到的每個(gè)人臉的名稱
names = []
我們首先加載包含每個(gè)人的姓名和相應(yīng)的面部嵌入列表的字典。接下來(lái),我們使用 OpenCV 加載輸入圖像,并使用face_encodings()
函數(shù)為圖像中的每個(gè)人臉生成人臉嵌入。
下一步是循環(huán)面部嵌入并將其與數(shù)據(jù)集中每個(gè)人的面部嵌入進(jìn)行比較。我們需要另一個(gè)輔助函數(shù)來(lái)計(jì)算當(dāng)前面部嵌入與數(shù)據(jù)集中每個(gè)人的面部嵌入之間的距離。
如果當(dāng)前人臉嵌入與數(shù)據(jù)庫(kù)中的人臉嵌入之間的距離小于閾值,則該人臉被視為匹配,因此我們將當(dāng)前人的“匹配數(shù)”增加 1。
通過(guò)查看代碼更容易理解這個(gè)邏輯。打開(kāi)utils.py
文件并添加以下代碼:
def nb_of_matches(known_encodings, unknown_encoding):
# 計(jì)算當(dāng)前人臉編碼與數(shù)據(jù)庫(kù)中所有人臉編碼之間的歐氏距離
distances = np.linalg.norm(known_encodings - unknown_encoding, axis=1)
# 僅保留小于閾值的距離
small_distances = distances <= 0.6
# 返回匹配數(shù)量
return sum(small_distances)
nb_of_matches **()
**函數(shù)采用兩個(gè)參數(shù):數(shù)據(jù)集中每個(gè)人的面部嵌入列表 ( known_encodings
) 和輸入圖像中當(dāng)前面部的面部嵌入 ( unknown_encoding
)。
它計(jì)算當(dāng)前人臉編碼與數(shù)據(jù)庫(kù)中所有人臉編碼之間的歐幾里德距離。然后,它僅保留小于閾值的距離(如果距離小于閾值,則認(rèn)為面部匹配)。
最后,將距離小于閾值的次數(shù)相加,得到當(dāng)前人臉的匹配數(shù)?,F(xiàn)在,我們可以循環(huán)輸入圖像中每個(gè)人臉的人臉嵌入,并使用nb_of_matches()
函數(shù)來(lái)獲取每個(gè)人臉的匹配數(shù)。
# 導(dǎo)入輔助函數(shù)
from utils import nb_of_matches
# 循環(huán)遍歷編碼
for encoding in encodings:
# 初始化一個(gè)字典來(lái)存儲(chǔ)人名和匹配次數(shù)
counts = {}
# 循環(huán)遍歷已知編碼
for (name, encodings) in name_encodings_dict.items():
# 計(jì)算當(dāng)前編碼與已知人臉編碼之間的匹配次數(shù),并將匹配次數(shù)存儲(chǔ)在字典中
counts[name] = nb_of_matches(encodings, encoding)
# 檢查所有匹配次數(shù)是否都等于0,如果沒(méi)有任何名稱匹配,則將名稱設(shè)置為"Unknown"
if all(count == 0 for count in counts.values()):
name = "Unknown"
# 否則,獲取匹配次數(shù)最高的名稱
else:
name = max(counts, key=counts.get)
# 將名稱添加到名稱列表中
names.append(name)
因此,我們首先初始化一個(gè)字典來(lái)跟蹤每個(gè)人的匹配次數(shù)。然后,使用已知編碼的字典,我們調(diào)用nb_of_matches()
函數(shù)來(lái)獲取當(dāng)前面部編碼的匹配次數(shù),并將其存儲(chǔ)在計(jì)數(shù)字典中。
接下來(lái),我們使用counts
字典來(lái)獲取匹配次數(shù)最多的人的名字。如果沒(méi)有任何人匹配(所有匹配次數(shù)等于0),我們將名稱設(shè)置為“未知”。然后,我們將該名稱添加到名稱列表中。
最后一步是在輸入圖像中的每個(gè)人臉周圍繪制一個(gè)矩形,并在矩形頂部寫下人的名字。
# 使用`face_rects`函數(shù)循環(huán)遍歷輸入圖像中人臉的矩形
for rect, name in zip(face_rects(image), names):
# 使用`rect`變量獲取每個(gè)人臉的邊界框
x1, y1, x2, y2 = rect.left(), rect.top(), rect.right(), rect.bottom()
# 繪制人臉的邊界框以及人名
cv2.rectangle(image, (x1, y1), (x2, y2), (0, 255, 0), 2)
cv2.putText(image, name, (x1, y1 - 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.75, (0, 255, 0), 2)
# 顯示輸出圖像
cv2.imshow("image", image)
cv2.waitKey(0)
我們使用 face_rects()
函數(shù)返回輸入圖像中每個(gè)面的矩形列表。這些矩形由Dlib庫(kù)提供。我們遍歷矩形并獲取每個(gè)面的邊界框。然后,我們?cè)诿繌埬樦車嬕粋€(gè)矩形,并在矩形頂部寫下人的名字。最后,我們使用OpenCV顯示輸出圖像。
現(xiàn)在,是時(shí)候測(cè)試我們的人臉識(shí)別算法了。我已經(jīng)在示例文件夾中添加了一些圖像。以下是我們的人臉識(shí)別算法的輸出示例:
?在這個(gè)例子中,我測(cè)試了示例文件夾內(nèi)的一些圖像。正如您所看到的,算法正確識(shí)別了圖像中每個(gè)人的面孔。現(xiàn)在,如果輸入圖像中有多個(gè)人怎么辦?讓我們看一個(gè)例子:
正如您所看到的,算法正確識(shí)別了同一圖像中的三張臉。如果某個(gè)人的面孔不在我們的數(shù)據(jù)集中怎么辦?讓我們看一個(gè)例子:
?我們的數(shù)據(jù)集不包含右側(cè)人的圖像,但我們的算法足夠聰明,可以將他標(biāo)記為“Unknown
”人。關(guān)于視頻中的人臉識(shí)別,代碼與圖像代碼幾乎相同。唯一的區(qū)別是我們需要循環(huán)播放視頻的幀。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-773166.html
六、總結(jié)
本文介紹了人臉識(shí)別技術(shù)在計(jì)算機(jī)視覺(jué)領(lǐng)域的應(yīng)用和發(fā)展。首先,文章提到了計(jì)算機(jī)視覺(jué)技術(shù)在人工智能中的成熟度和廣泛應(yīng)用,特別是在圖像處理、目標(biāo)檢測(cè)和語(yǔ)義分割等領(lǐng)域的突破。然后,文章指出了公司在人臉識(shí)別領(lǐng)域進(jìn)行自主研發(fā)與應(yīng)用的需求和背景,包括業(yè)務(wù)背景、平臺(tái)架構(gòu)、部署架構(gòu)和功能需求等。接著,文章介紹了如何使用Dlib庫(kù)和深度學(xué)習(xí)來(lái)實(shí)現(xiàn)人臉識(shí)別,并利用預(yù)訓(xùn)練網(wǎng)絡(luò)和OpenCV庫(kù)進(jìn)行圖像處理。最后,文章概述了人臉識(shí)別的定義、應(yīng)用和步驟,包括人臉檢測(cè)、面部對(duì)齊、面部編碼和人臉識(shí)別。文章還提到了基于深度學(xué)習(xí)的人臉識(shí)別算法及其工作原理。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-773166.html
到了這里,關(guān)于基于OpenCV和Dlib的深度學(xué)習(xí)人臉識(shí)別技術(shù)實(shí)踐與應(yīng)用的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!