人臉識(shí)別實(shí)戰(zhàn):使用Python OpenCV 和深度學(xué)習(xí)進(jìn)行人臉識(shí)別
在本文中,將學(xué)習(xí)如何使用 OpenCV、Python 和深度學(xué)習(xí)執(zhí)行面部識(shí)別。
首先簡(jiǎn)要討論基于深度學(xué)習(xí)的面部識(shí)別的工作原理,包括“深度度量學(xué)習(xí)”的概念。 然后,我將幫助您安裝實(shí)際執(zhí)行人臉識(shí)別所需的庫(kù)。 最后,我們將為靜止圖像和視頻流實(shí)現(xiàn)人臉識(shí)別。
安裝人臉識(shí)別庫(kù)
為了使用 Python 和 OpenCV 執(zhí)行人臉識(shí)別,我們需要安裝兩個(gè)額外的庫(kù):
dlib
face_recognition
安裝 dlib
pip install dlib
1
或者你可以從源代碼編譯:
git clone https://github.com/davisking/dlib.git cd dlib mkdir build cd build cmake .. -DUSE_AVX_INSTRUCTIONS=1 cmake --build . cd .. python setup.py install --yes USE_AVX_INSTRUCTIONS
1
2
3
4
5
6
7
8
如果安裝失敗可以嘗試:
pip install dlib-bin
1
效果一樣,但是這樣做只有能安裝CPU版本,缺點(diǎn)就是慢。
安裝支持 GPU 的 dlib(可選)
如果你有一個(gè)兼容 CUDA 的 GPU,你可以安裝支持 GPU 的 dlib,使面部識(shí)別更快、更高效。 為此,我建議從源代碼安裝 dlib,因?yàn)槟梢愿玫乜刂茦?gòu)建:
$ git clone https://github.com/davisking/dlib.git $ cd dlib $ mkdir build $ cd build $ cmake .. -DDLIB_USE_CUDA=1 -DUSE_AVX_INSTRUCTIONS=1 $ cmake --build . $ cd .. $ python setup.py install --yes USE_AVX_INSTRUCTIONS --yes DLIB_USE_CUDA
1
2
3
4
5
6
7
8
建議用GPU版本,如果安裝失敗參考這篇文章:
https://blog.csdn.net/hhhhhhhhhhwwwwwwwwww/article/details/121470556?spm=1001.2014.3001.5501
安裝 face_recognition 包
face_recognition 模塊可以通過(guò)一個(gè)簡(jiǎn)單的 pip 命令安裝:
pip install face_recognition
1
安裝 imutils
您還需要我的便利功能包 imutils。 你可以通過(guò) pip 將它安裝在你的 Python 虛擬環(huán)境中:
pip install imutils
1
人臉識(shí)別數(shù)據(jù)集
數(shù)據(jù)集來(lái)源網(wǎng)絡(luò)搜索,我選取了幾名大家認(rèn)識(shí)的人物,有Biden、chenglong、mayun、Trump、yangmi、zhaoliying等。每個(gè)人物放入3-4張圖片,如下圖:
獲得此圖像數(shù)據(jù)集,我們將:
為數(shù)據(jù)集中的每個(gè)人臉創(chuàng)建 128 維嵌入
使用這些嵌入來(lái)識(shí)別圖像和視頻流中人物的面部
制作數(shù)據(jù)集的方法:
人臉識(shí)別項(xiàng)目結(jié)構(gòu)
myface ├── dataset ├─dataset │ ├─Biden │ ├─chenglong │ ├─mayun │ ├─Trump │ ├─yangmi │ └─zhaoliying ├── encode_faces.py ├── recognize_faces_image.py ├── recognize_faces_video.py └── encodings.pickle
1
2
3
4
5
6
7
8
9
10
11
12
13
14
我們的項(xiàng)目有 4 個(gè)頂級(jí)目錄:
dataset/ :包含六個(gè)字符的面部圖像,根據(jù)它們各自的名稱(chēng)組織到子目錄中。 。
output/ :這是您可以存儲(chǔ)處理過(guò)的人臉識(shí)別視頻的地方。 我要把我的一個(gè)留在文件夾里——原侏羅紀(jì)公園電影中的經(jīng)典“午餐場(chǎng)景”。
videos/ :輸入視頻應(yīng)存儲(chǔ)在此文件夾中。 該文件夾還包含“午餐場(chǎng)景”視頻,但尚未經(jīng)過(guò)我們的人臉識(shí)別系統(tǒng)。
我們?cè)诟夸浵逻€有 6 個(gè)文件:
encode_faces.py :人臉的編碼(128 維向量)是用這個(gè)腳本構(gòu)建的。
identify_faces_image.py :識(shí)別單個(gè)圖像中的人臉(基于數(shù)據(jù)集中的編碼)。
identify_faces_video.py :識(shí)別來(lái)自網(wǎng)絡(luò)攝像頭的實(shí)時(shí)視頻流中的人臉并輸出視頻。
encodings.pickle :面部識(shí)別編碼通過(guò) encode_faces.py 從您的數(shù)據(jù)集生成,然后序列化到磁盤(pán)。
創(chuàng)建圖像數(shù)據(jù)集后(使用 search_bing_api.py ),我們將運(yùn)行 encode_faces.py 來(lái)構(gòu)建嵌入。 然后,我們將運(yùn)行識(shí)別腳本來(lái)實(shí)際識(shí)別人臉。
使用 OpenCV 和深度學(xué)習(xí)對(duì)人臉進(jìn)行編碼
在識(shí)別圖像和視頻中的人臉之前,我們首先需要量化訓(xùn)練集中的人臉。 請(qǐng)記住,我們實(shí)際上并不是在這里訓(xùn)練網(wǎng)絡(luò)——網(wǎng)絡(luò)已經(jīng)被訓(xùn)練為在大約 300 萬(wàn)張圖像的數(shù)據(jù)集上創(chuàng)建 128 維嵌入。
當(dāng)然可以從頭開(kāi)始訓(xùn)練網(wǎng)絡(luò),甚至可以微調(diào)現(xiàn)有模型的權(quán)重。一般情況。
使用預(yù)訓(xùn)練網(wǎng)絡(luò)然后使用它為我們數(shù)據(jù)集中的 29張人臉中的每一張構(gòu)建 128 維嵌入更容易。
然后,在分類(lèi)過(guò)程中,我們可以使用一個(gè)簡(jiǎn)單的 k-NN 模型 + 投票來(lái)進(jìn)行最終的人臉?lè)诸?lèi)。 其他傳統(tǒng)的機(jī)器學(xué)習(xí)模型也可以在這里使用。 要構(gòu)建我們的人臉嵌入,
請(qǐng)新建 encode_faces.py:
# import the necessary packages from imutils import paths import face_recognition import argparse import pickle import cv2 import os dataset_path='dataset' encodings_path='encodings.pickle' detection_method='cnn' # 獲取數(shù)據(jù)集中輸入圖像的路徑 print("[INFO] quantifying faces...") imagePaths = list(paths.list_images(dataset_path)) # 初始化已知編碼和已知名稱(chēng)的列表 knownEncodings = [] knownNames = [] # 遍歷圖像路徑 for (i, imagePath) in enumerate(imagePaths): # 從圖片路徑中提取人名 print("[INFO] processing image {}/{}".format(i + 1, len(imagePaths))) name = imagePath.split(os.path.sep)[-2] # 加載輸入圖像并從 BGR 轉(zhuǎn)換(OpenCV 排序) # 到 dlib 排序(RGB) image = cv2.imread(imagePath) rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) # 檢測(cè)邊界框的 (x, y) 坐標(biāo) # 對(duì)應(yīng)輸入圖像中的每個(gè)人臉 boxes = face_recognition.face_locations(rgb, model=detection_method) # 計(jì)算人臉的嵌入 encodings = face_recognition.face_encodings(rgb, boxes) # 遍歷 encodings for encoding in encodings: # 將每個(gè)編碼 + 名稱(chēng)添加到我們的已知名稱(chēng)集中 # 編碼 knownEncodings.append(encoding) knownNames.append(name)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
導(dǎo)入包,定義全局變量
變量的含義:
dataset_path:數(shù)據(jù)集的路徑。
encodings_path :我們的人臉編碼被寫(xiě)入這個(gè)參數(shù)指向的文件路徑。
detection_method :在我們對(duì)圖像中的人臉進(jìn)行編碼之前,我們首先需要檢測(cè)它們。 或者兩種人臉檢測(cè)方法包括 hog 或 cnn 。
現(xiàn)在我們已經(jīng)定義了我們的參數(shù),讓我們獲取數(shù)據(jù)集中文件的路徑(以及執(zhí)行兩個(gè)初始化):
輸入數(shù)據(jù)集目錄的路徑來(lái)構(gòu)建其中包含的所有圖像路徑的列表。
在循環(huán)之前分別初始化兩個(gè)列表 knownEncodings 和 knownNames 。 這兩個(gè)列表將包含數(shù)據(jù)集中每個(gè)人的面部編碼和相應(yīng)的姓名。
這個(gè)循環(huán)將循環(huán) 19次,對(duì)應(yīng)于我們?cè)跀?shù)據(jù)集中的 19張人臉圖像。
遍歷每個(gè)圖像的路徑。從 imagePath中提取人名。 然后讓我們加載圖像,同時(shí)將 imagePath 傳遞給 cv2.imread。 OpenCV 使用BGR 顏色通道,但 dlib 實(shí)際上期望 RGB。 face_recognition 模塊使用 dlib ,交換顏色空間。 接下來(lái),讓我們定位人臉并計(jì)算編碼:
對(duì)于循環(huán)的每次迭代,我們將檢測(cè)一張臉,查找/定位了她的面孔,從而生成了面孔框列表。 我們將兩個(gè)參數(shù)傳遞給 face_recognition.face_locations 方法:
rgb :我們的 RGB 圖像。
model:cnn 或 hog(該值包含在與“detection_method”鍵關(guān)聯(lián)的命令行參數(shù)字典中)。 CNN方法更準(zhǔn)確但速度更慢。 HOG 速度更快,但準(zhǔn)確度較低。
然后,將面部的邊界框轉(zhuǎn)換為 128 個(gè)數(shù)字的列表。這稱(chēng)為將面部編碼為向量,而 face_recognition.face_encodings 方法會(huì)處理它。 編碼和名稱(chēng)附加到適當(dāng)?shù)牧斜恚╧nownEncodings 和 knownNames)。然后,將繼續(xù)對(duì)數(shù)據(jù)集中的所有 19張圖像執(zhí)行此操作。
# dump the facial encodings + names to disk print("[INFO] serializing encodings...") data = {"encodings": knownEncodings, "names": knownNames} f = open(args["encodings"], "wb") f.write(pickle.dumps(data)) f.close()
1
2
3
4
5
6
構(gòu)造了一個(gè)帶有兩個(gè)鍵的字典—— “encodings” 和 “names” 。
將名稱(chēng)和編碼轉(zhuǎn)儲(chǔ)到磁盤(pán)以備將來(lái)調(diào)用。運(yùn)行encode_faces.py
D:\ProgramData\Anaconda3\python.exe D:/cv/myface/encode_faces.py [INFO] quantifying faces... [INFO] processing image 1/19 [INFO] processing image 2/19 [INFO] processing image 3/19 [INFO] processing image 4/19 [INFO] processing image 5/19 [INFO] processing image 6/19 [INFO] processing image 7/19 [INFO] processing image 8/19 [INFO] processing image 9/19 [INFO] processing image 10/19 [INFO] processing image 11/19 [INFO] processing image 12/19 [INFO] processing image 13/19 [INFO] processing image 14/19 [INFO] processing image 15/19 [INFO] processing image 16/19 [INFO] processing image 17/19 [INFO] processing image 18/19 [INFO] processing image 19/19 [INFO] serializing encodings... Process finished with exit code 0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
正如輸出中看到的,我們現(xiàn)在有一個(gè)名為 encodings.pickle 的文件——該文件包含我們數(shù)據(jù)集中每個(gè)人臉的 128 維人臉嵌入。
識(shí)別圖像中的人臉
現(xiàn)在我們已經(jīng)為數(shù)據(jù)集中的每個(gè)圖像創(chuàng)建了 128 維人臉嵌入,現(xiàn)在我們可以使用 OpenCV、Python 和深度學(xué)習(xí)來(lái)識(shí)別圖像中的人臉。 打開(kāi)recognize_faces_image.py 并插入以下代碼:
import face_recognition import pickle import cv2 encodings_path='encodings.pickle' image_path='11.jpg' detection_method='cnn' # load the known faces and embeddings print("[INFO] loading encodings...") data = pickle.loads(open(encodings_path, "rb").read()) # 加載輸入圖像并將其從 BGR 轉(zhuǎn)換為 RGB image = cv2.imread(image_path) rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) # 檢測(cè)輸入圖像中每個(gè)人臉對(duì)應(yīng)的邊界框的 (x, y) 坐標(biāo),然后計(jì)算每個(gè)人臉的面部嵌入 print("[INFO] recognizing faces...") boxes = face_recognition.face_locations(rgb,model=detection_method) encodings = face_recognition.face_encodings(rgb, boxes) # 初始化檢測(cè)到的每個(gè)人臉的名字列表 names = [] # 循環(huán)面部嵌入 for encoding in encodings: # 嘗試將輸入圖像中的每個(gè)人臉與我們已知的編碼相匹配 matches = face_recognition.compare_faces(data["encodings"],encoding) name = "Unknown" # 檢查是否有匹配的 if True in matches: # 找到所有匹配人臉的索引,然后初始化一個(gè)字典來(lái)計(jì)算每個(gè)人臉被匹配的總次數(shù) matchedIdxs = [i for (i, b) in enumerate(matches) if b] counts = {} # 遍歷匹配的索引并為每個(gè)識(shí)別出的人臉維護(hù)一個(gè)計(jì)數(shù) for i in matchedIdxs: name = data["names"][i] counts[name] = counts.get(name, 0) + 1 # 確定獲得最多票數(shù)的識(shí)別人臉(注意:如果出現(xiàn)不太可能的平局,Python 將選擇字典中的第一個(gè)條目) name = max(counts, key=counts.get) # 更新names names.append(name) # 遍歷識(shí)別的人臉 for ((top, right, bottom, left), name) in zip(boxes, names): # 在圖像上繪制預(yù)測(cè)的人臉名稱(chēng) cv2.rectangle(image, (left, top), (right, bottom), (0, 255, 0), 2) y = top - 15 if top - 15 > 15 else top + 15 cv2.putText(image, name, (left, y), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (0, 255, 0), 2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
解析三個(gè)參數(shù):
encodings_path:包含我們的面部編碼的pickle文件的路徑。
image_path:這是正在進(jìn)行面部識(shí)別的圖像。
detection-method :你現(xiàn)在應(yīng)該很熟悉這個(gè)了——根據(jù)你系統(tǒng)的能力,我們要么使用 hog 方法,要么使用 cnn 方法。 為了速度,選擇 hog ,為了準(zhǔn)確,選擇 cnn 。
然后,讓我們加載預(yù)先計(jì)算的編碼 + 人臉名稱(chēng),然后為輸入圖像構(gòu)建 128 維人臉編碼。
加載編碼和人臉名稱(chēng)。
加載輸入圖像并將其轉(zhuǎn)換為 rgb 顏色通道排序。
繼續(xù)檢測(cè)輸入圖像中的所有人臉,并計(jì)算它們的 128 維編碼。
為檢測(cè)到的每個(gè)人臉初始化names列表。
接下來(lái),讓我們遍歷面部編碼:
開(kāi)始遍歷從輸入圖像計(jì)算出的人臉編碼。 嘗試使用 face_recognition.compare_faces將輸入圖像(編碼)中的每個(gè)人臉與我們已知的編碼數(shù)據(jù)集進(jìn)行匹配。
此函數(shù)返回 True / False 值列表,數(shù)據(jù)集中的每個(gè)圖像對(duì)應(yīng)一個(gè)值。
在內(nèi)部,compare_faces 函數(shù)正在計(jì)算候選嵌入與我們數(shù)據(jù)集中所有人臉之間的歐幾里德距離:
如果距離低于某個(gè)容差(容差越小,我們的面部識(shí)別系統(tǒng)就會(huì)越嚴(yán)格),那么我們返回 True ,表示面部匹配。
否則,如果距離高于容差閾值,我們將返回 False,因?yàn)槿四槻黄ヅ洹?/p>
本質(zhì)上利用 k-NN 模型進(jìn)行分類(lèi)。 name 變量最終將保存此人的姓名字符串——現(xiàn)在,我們將其保留為“Unknown”,以防沒(méi)有“投票”。
計(jì)算每個(gè)名字的“投票”數(shù),統(tǒng)計(jì)投票數(shù),并選擇對(duì)應(yīng)票數(shù)最多的人的名字。
如果匹配中有任何 True 投票,確定這些 True 值在匹配中的位置的索引。
然后初始化一個(gè)名為 counts 的字典,它將以字符名稱(chēng)作為鍵,將投票數(shù)作為值。然后循環(huán)匹配的Idxs并設(shè)置與每個(gè)名稱(chēng)關(guān)聯(lián)的值,同時(shí)根據(jù)需要在 counts 中增加它。繼續(xù)并遍歷每個(gè)人的邊界框和標(biāo)記名稱(chēng),并將它們繪制在輸出圖像上以進(jìn)行可視化:
cv2.imshow("Image", image) cv2.imwrite("001.jpg",image) cv2.waitKey(0)
1
2
3
4
展示圖片
保存圖片。
運(yùn)行recognize_faces_image.py 腳本:
識(shí)別視頻中的人臉
現(xiàn)在我們已經(jīng)將人臉識(shí)別應(yīng)用于圖像,讓我們也將人臉識(shí)別應(yīng)用于視頻。
新建 identify_faces_video.py 并插入以下代碼:
import imutils import pickle import time import cv2 # construct the argument parser and parse the arguments encodings_path='encodings.pickle' output='output.mp4' display_type=0 detection_method='cnn'
1
2
3
4
5
6
7
8
9
10
導(dǎo)入包,然后定義全局變量
output : 輸出視頻的路徑。
display_type :指示腳本在屏幕上顯示框架的標(biāo)志。 值為 1 時(shí)顯示,值為 0 時(shí)不會(huì)將輸出幀顯示到我們的屏幕上。
加載我們的編碼并啟動(dòng)我們的 cv2.VideoCapture:
# load the known faces and embeddings print("[INFO] loading encodings...") data = pickle.loads(open(encodings_path, "rb").read()) # 初始化視頻流和輸出視頻文件的指針,然后讓相機(jī)傳感器預(yù)熱 print("[INFO] starting video stream...") #vs = VideoStream(src=0).start() vs=cv2.VideoCapture('1.MP4') writer = None time.sleep(2.0) # loop over frames from the video file stream while True: # grab the frame from the threaded video stream ret,frame = vs.read() if not ret: print("Can't receive frame (stream end?). Exiting ...") break # 將輸入幀從 BGR 轉(zhuǎn)換為 RGB,然后將其調(diào)整為 750 像素的寬度(以加快處理速度) rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) rgb = imutils.resize(frame, width=750) r = frame.shape[1] / float(rgb.shape[1]) # 檢測(cè)輸入幀中每個(gè)人臉對(duì)應(yīng)的邊界框的 (x, y) 坐標(biāo),然后計(jì)算每個(gè)人臉的人臉嵌入 boxes = face_recognition.face_locations(rgb, model=detection_method) encodings = face_recognition.face_encodings(rgb, boxes) names = [] # 循環(huán)面部嵌入 for encoding in encodings: # 嘗試將輸入圖像中的每個(gè)人臉與我們已知的編碼相匹配 matches = face_recognition.compare_faces(data["encodings"], encoding) name = "Unknown" # 檢查我們是否找到了匹配項(xiàng) if True in matches: # 找到所有匹配人臉的索引,然后初始化一個(gè)字典來(lái)計(jì)算每個(gè)人臉被匹配的總次數(shù) matchedIdxs = [i for (i, b) in enumerate(matches) if b] counts = {} # 遍歷匹配的索引并為每個(gè)識(shí)別出的人臉維護(hù)一個(gè)計(jì)數(shù) for i in matchedIdxs: name = data["names"][i] counts[name] = counts.get(name, 0) + 1 # 確定獲得最多票數(shù)的識(shí)別人臉(注意:如果出現(xiàn)不太可能的平局,Python 將選擇字典中的第一個(gè)條目) name = max(counts, key=counts.get) # 更新names names.append(name) # 遍歷識(shí)別的人臉 for ((top, right, bottom, left), name) in zip(boxes, names): # 重新調(diào)整人臉坐標(biāo) top = int(top * r) right = int(right * r) bottom = int(bottom * r) left = int(left * r) # 在圖像上繪制預(yù)測(cè)的人臉名稱(chēng) cv2.rectangle(frame, (left, top), (right, bottom), (0, 255, 0), 2) y = top - 15 if top - 15 > 15 else top + 15 cv2.putText(frame, name, (left, y), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (0, 255, 0), 2) if writer is None and output is not None: fourcc = cv2.VideoWriter_fourcc(*"MJPG") writer = cv2.VideoWriter(output, fourcc, 20, (frame.shape[1], frame.shape[0]), True) # 如果 writer 不是 None,則將識(shí)別出人臉的幀寫(xiě)入磁盤(pán) if writer is not None: writer.write(frame) # 檢查我們是否應(yīng)該將輸出幀顯示到屏幕上 if display_type > 0: cv2.imshow("Frame", frame) key = cv2.waitKey(1) & 0xFF # if the `q` key was pressed, break from the loop if key == ord("q"): break
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
在這里我用視頻代替攝像頭。
第一步是從視頻流中抓取一幀。 上述代碼塊與前一個(gè)腳本中的行幾乎相同,不同之處在于這是一個(gè)視頻幀而不是靜態(tài)圖像。
接下來(lái),讓我們遍歷與我們剛剛找到的人臉相關(guān)的人臉編碼。
在循環(huán)中,遍歷每個(gè)編碼并嘗試匹配人臉。 如果找到匹配項(xiàng),計(jì)算數(shù)據(jù)集中每個(gè)名字的投票數(shù)。 然后提取最高票數(shù),即與人臉相關(guān)的名稱(chēng)。
然后,遍歷識(shí)別出的人臉并繼續(xù)在人臉周?chē)L制一個(gè)框,并在人臉上方顯示人的姓名。
如果設(shè)置了 display 命令行參數(shù),顯示框架并檢查是否按下了退出鍵(“q”),此時(shí)我們將跳出 循環(huán)。 最后,讓我們履行我們的家政職責(zé):
# do a bit of cleanup cv2.destroyAllWindows() #vs.stop() vs.release() # check to see if the video writer point needs to be released if writer is not None: writer.release()
1
2
3
4
5
6
7
清理并釋放顯示、視頻流和視頻編寫(xiě)器。
運(yùn)行recognize_faces_video.py腳本查看識(shí)別效果
視頻文件識(shí)別結(jié)果
完整的代碼和數(shù)據(jù)集:
https://download.csdn.net/download/hhhhhhhhhhwwwwwwwwww/46802864
OpenCV Python 人臉識(shí)別服務(wù) FRS
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶(hù)投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。