人臉識(shí)別越來(lái)越流行,我們大多數(shù)人已經(jīng)在使用它,甚至沒(méi)有意識(shí)到它。無(wú)論是簡(jiǎn)單的 Facebook 標(biāo)簽建議、Snapchat 過(guò)濾器還是高級(jí)機(jī)場(chǎng)安全監(jiān)控,人臉識(shí)別已經(jīng)在其中發(fā)揮了魔力。中國(guó)已開(kāi)始在學(xué)校使用人臉識(shí)別來(lái)監(jiān)控學(xué)生的出勤和行為。零售店已開(kāi)始使用人臉識(shí)別對(duì)其客戶(hù)進(jìn)行分類(lèi)并隔離有欺詐歷史的人。隨著更多的變化正在進(jìn)行中,毫無(wú)疑問(wèn),這項(xiàng)技術(shù)將在不久的將來(lái)隨處可見(jiàn)。
在本教程中,我們將學(xué)習(xí)如何使用 Raspberry Pi 上的 OpenCV 庫(kù)構(gòu)建我們自己的人臉識(shí)別系統(tǒng)。將此系統(tǒng)安裝在便攜式 Raspberry Pi 上的優(yōu)勢(shì)在于,您可以將其安裝在任何地方以將其用作監(jiān)控系統(tǒng)。與所有人臉識(shí)別系統(tǒng)一樣,本教程將涉及兩個(gè) python 腳本,一個(gè)是Trainer 程序,它將分析特定人的一組照片并創(chuàng)建一個(gè)數(shù)據(jù)集(YML 文件)。第二個(gè)程序是識(shí)別器程序它檢測(cè)人臉,然后使用這個(gè) YML 文件來(lái)識(shí)別人臉并提及人名。我們將在此處討論的兩個(gè)程序都適用于 Raspberry Pi (Linux),但也適用于 Windows 計(jì)算機(jī),只需稍作改動(dòng)。
如前所述,我們將使用 OpenCV 庫(kù)來(lái)檢測(cè)和識(shí)別人臉。因此,在繼續(xù)本教程之前,請(qǐng)確保在 Pi 上安裝 OpenCV 庫(kù)。還要使用 2A 適配器為您的 Pi 供電,并通過(guò) HDMI 電纜將其連接到顯示器,因?yàn)槲覀儗o(wú)法通過(guò) SSH 獲得視頻輸出。
人臉識(shí)別如何與 OpenCV 配合使用
在我們開(kāi)始之前,重要的是要了解人臉檢測(cè)和人臉識(shí)別是兩個(gè)不同的東西。在人臉檢測(cè)中,僅檢測(cè)到一個(gè)人的臉,該軟件將不知道該人是誰(shuí)。在人臉識(shí)別中,軟件不僅會(huì)檢測(cè)人臉,還會(huì)識(shí)別人。現(xiàn)在,應(yīng)該清楚我們需要在執(zhí)行人臉識(shí)別之前執(zhí)行人臉檢測(cè)。我無(wú)法解釋 OpenCV 是如何準(zhǔn)確檢測(cè)人臉或任何其他物體的。
來(lái)自網(wǎng)絡(luò)攝像頭的視頻饋送只不過(guò)是一長(zhǎng)串不斷更新的靜止圖像。這些圖像中的每一個(gè)都只是將不同值的像素放在各自的位置上的集合。那么程序如何從這些像素中檢測(cè)出人臉并進(jìn)一步識(shí)別其中的人呢?它背后有很多算法,試圖解釋它們超出了本文的范圍,但由于我們使用的是 OpenCV 庫(kù),因此執(zhí)行面部識(shí)別非常簡(jiǎn)單,無(wú)需深入了解概念
在 OpenCV 中使用級(jí)聯(lián)分類(lèi)器進(jìn)行人臉檢測(cè)
只有當(dāng)我們能夠檢測(cè)到一張臉時(shí),我們才能識(shí)別或記住它。為了檢測(cè)諸如人臉之類(lèi)的對(duì)象,OpenCV 使用了一種叫做分類(lèi)器的東西。這些分類(lèi)器是預(yù)先訓(xùn)練的數(shù)據(jù)集(XML 文件),可用于檢測(cè)我們案例中的特定對(duì)象,即人臉。您可以在此處了解有關(guān)人臉檢測(cè)分類(lèi)器的更多信息。除了檢測(cè)人臉,分類(lèi)器還可以檢測(cè)鼻子、眼睛、車(chē)牌、微笑等其他物體。
Python中對(duì)象檢測(cè)的分類(lèi)器
或者,OpenCV 還允許您創(chuàng)建自己的分類(lèi)器,該分類(lèi)器可用于通過(guò)訓(xùn)練級(jí)聯(lián)分類(lèi)器來(lái)檢測(cè)圖像中的任何其他對(duì)象。在本教程中,我們將使用一個(gè)名為“haarcascade_frontalface_default.xml”的分類(lèi)器,它將從正面位置檢測(cè)人臉。我們將在編程部分看到更多關(guān)于如何使用分類(lèi)器的信息。
安裝所需的軟件包
確保已安裝 pip,然后繼續(xù)安裝以下軟件包。
安裝dlib: Dlib 是一個(gè)用于現(xiàn)實(shí)世界機(jī)器學(xué)習(xí)和數(shù)據(jù)分析應(yīng)用程序的工具包。要安裝 dlib,只需在終端中輸入以下命令
點(diǎn)安裝 dlib
這應(yīng)該會(huì)安裝dlib,成功后您將看到這樣的屏幕。
安裝枕頭:枕頭也稱(chēng)為 PIL 代表 Python Imaging Library,用于以不同格式打開(kāi)、操作和保存圖像。要安裝 PIL,請(qǐng)使用以下命令
點(diǎn)安裝枕頭
安裝后,您將收到一條成功消息,如下所示
安裝 face_recognition: python 的 face_recognition 庫(kù)被認(rèn)為是識(shí)別和操作人臉的最簡(jiǎn)單的庫(kù)。我們將使用這個(gè)庫(kù)來(lái)訓(xùn)練和識(shí)別人臉。要安裝這個(gè)庫(kù),請(qǐng)按照命令
pip install face_recognition –no –cache-dir
成功安裝后,您應(yīng)該會(huì)看到如下所示的屏幕。該庫(kù)很重,大多數(shù)人會(huì)面臨內(nèi)存超出問(wèn)題,因此我使用“--no –cache-dir”代碼安裝庫(kù)而不保存緩存文件。
面部訓(xùn)練師計(jì)劃
讓我們看一下Face_Traineer.py程序。該程序的目標(biāo)是打開(kāi)Face_Images目錄中的所有圖像并搜索人臉。一旦檢測(cè)到人臉,它會(huì)裁剪人臉并將其轉(zhuǎn)換為灰度,然后轉(zhuǎn)換為 numpy 數(shù)組,然后我們最終使用我們之前安裝的face_recognition庫(kù)來(lái)訓(xùn)練并將其保存為名為face-trainner.yml的文件。此文件中的數(shù)據(jù)稍后可用于識(shí)別人臉。最后給出了完整的 Trainer 程序,這里將解釋最重要的幾行。
我們通過(guò)導(dǎo)入所需的模塊開(kāi)始程序。cv2 模塊用于圖像處理,numpy 用于將圖像轉(zhuǎn)換為數(shù)學(xué)等價(jià)物,os模塊用于導(dǎo)航目錄,PIL 用于處理圖像。
?
import cv2 #用于圖像處理 import numpy as np #用于將圖像轉(zhuǎn)換為數(shù)值數(shù)組 import os #用于處理 來(lái)自 PIL 的目錄 import Image #用于處理圖像的枕頭庫(kù)
?
接下來(lái)我們必須使用 haarcascade_frontalface_default.xml 分類(lèi)器來(lái)檢測(cè)圖像中的人臉。確保您已將此 xml 文件放在項(xiàng)目文件夾中,否則您將面臨錯(cuò)誤。然后我們使用識(shí)別器變量來(lái)創(chuàng)建局部二進(jìn)制模式直方圖 (LBPH) 人臉識(shí)別器。
?
face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml') 識(shí)別器 = cv2.createLBPHFaceRecognizer()
?
然后我們必須進(jìn)入Face_Images目錄才能訪(fǎng)問(wèn)其中的圖像。該目錄應(yīng)放在您當(dāng)前的工作目錄 (CWD) 中。以下行用于進(jìn)入放置在 CWD 中的文件夾。
?
Face_Images = os.path.join(os.getcwd(), "Face_Images") #告訴程序我們將人臉圖像保存在哪里
?
然后我們使用for循環(huán)進(jìn)入目錄Face_Images的每個(gè)子目錄并打開(kāi)任何以 jpeg、jpg 或 png 結(jié)尾的文件。每個(gè)圖像的路徑存儲(chǔ)在一個(gè)名為 path 的變量中,而放置圖像的文件夾名稱(chēng)(將是人名)存儲(chǔ)在一個(gè)名為person_name的變量中。
?
for root, dirs, files in os.walk(Face_Images): #轉(zhuǎn)到人臉圖像目錄 for file in files: #檢查其中的每個(gè)目錄 if file.endswith("jpeg") or file.endswith("jpg") or file.endswith("png"): #對(duì)于以jpeg,jpg or png結(jié)尾的圖片文件 路徑 = os.path.join(根,文件) person_name = os.path.basename(root)
?
如果這個(gè)人的名字發(fā)生了變化,我們會(huì)增加一個(gè)名為Face_ID的變量,這將有助于我們?yōu)椴煌娜藫碛胁煌腇ace_ID,我們稍后將使用它來(lái)識(shí)別這個(gè)人的名字。
?
if pev_person_name!=person_name: #檢查人名是否改變 Face_ID=Face_ID+1 #如果是則增加ID計(jì)數(shù) pev_person_name = person_name
?
正如我們所知,OpenCV 處理灰度圖像比處理彩色圖像要容易得多,因?yàn)榭梢院雎?BGR 值。因此,為了減少圖像中的值,我們將其轉(zhuǎn)換為灰度,然后將圖像大小調(diào)整為 550,以使所有圖像保持一致。確保圖像中的臉部位于中間,否則臉部將被裁剪掉。最后將所有這些圖像轉(zhuǎn)換為 numpy 數(shù)組以獲得圖像的數(shù)學(xué)值。然后使用級(jí)聯(lián)分類(lèi)器檢測(cè)圖像中的人臉,并將結(jié)果存儲(chǔ)在一個(gè)名為faces的變量中。
?
Gery_Image = Image.open(path).convert("L") # 使用 Pillow Crop_Image = Gery_Image.resize( (550,550) , Image.ANTIALIAS) 將圖像轉(zhuǎn)換為灰度圖 #Crop the Gray Image to 550*550 (確保你的face is in center in all image) Final_Image = np.array(Crop_Image, "uint8") faces = face_cascade.detectMultiScale(Final_Image, scaleFactor=1.5, minNeighbors=5) #檢測(cè)所有樣本圖像中的人臉
?
一旦檢測(cè)到人臉,我們將裁剪該區(qū)域并將其視為我們的感興趣區(qū)域 (ROI)。ROI 區(qū)域?qū)⒂糜谟?xùn)練人臉識(shí)別器。我們必須將每個(gè) ROI 面附加到一個(gè)名為x_train的變量中。然后我們將這個(gè) ROI 值與 Face ID 值一起提供給識(shí)別器,識(shí)別器將為我們提供訓(xùn)練數(shù)據(jù)。這樣獲得的數(shù)據(jù)將被保存
?
for (x,y,w,h) in faces: roi = Final_Image[y:y+h, x:x+w] #crop the Region of Interest (ROI) x_train.append(roi) y_ID.append(Face_ID) 識(shí)別器.train(x_train, np.array(y_ID)) #創(chuàng)建訓(xùn)練數(shù)據(jù)矩陣 識(shí)別器.save("face-trainner.yml") #將矩陣保存為YML文件
?
當(dāng)你編譯這個(gè)程序時(shí),你會(huì)發(fā)現(xiàn)face-trainner.yml文件每次都會(huì)更新。因此,每當(dāng)您對(duì)Face_Images目錄中的照片進(jìn)行任何更改時(shí),請(qǐng)務(wù)必編譯此程序。編譯后,您將獲得打印的人臉 ID、路徑名、人名和 numpy 數(shù)組,如下所示,用于調(diào)試目的。
人臉識(shí)別程序
現(xiàn)在我們已經(jīng)準(zhǔn)備好經(jīng)過(guò)訓(xùn)練的數(shù)據(jù),我們現(xiàn)在可以使用它來(lái)識(shí)別人臉了。在人臉識(shí)別程序中,我們將從 USB 網(wǎng)絡(luò)攝像頭獲取實(shí)時(shí)視頻,然后將其轉(zhuǎn)換為圖像。然后我們必須使用我們的人臉檢測(cè)技術(shù)來(lái)檢測(cè)這些照片中的人臉,然后將其與我們之前創(chuàng)建的所有人臉 ID 進(jìn)行比較。如果我們找到匹配項(xiàng),我們就可以將臉部框起來(lái)并寫(xiě)下已識(shí)別的人的姓名。最后再次給出完整的程序,解釋如下。
該程序與訓(xùn)練程序有很多相似之處,因此導(dǎo)入我們之前使用的相同模塊并使用分類(lèi)器,因?yàn)槲覀冃枰俅螆?zhí)行人臉檢測(cè)。
?
import cv2 #用于圖像處理 import numpy as np #用于將圖像轉(zhuǎn)換為數(shù)值數(shù)組 import os #用于處理 來(lái)自 PIL 的目錄 import Image #用于處理圖像的枕頭庫(kù)
face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml') 識(shí)別器 = cv2.createLBPHFaceRecognizer()
?
接下來(lái)在變量標(biāo)簽中,您必須寫(xiě)下文件夾中提到的人員的姓名。確保您遵循相同的順序。就我而言,我的名字是“Aswinth”和“Elon”。
?
標(biāo)簽 = [“阿斯溫斯”,“埃隆馬斯克”]
?
然后我們必須將face-trainner.yml文件加載到我們的程序中,因?yàn)槲覀儽仨毷褂迷撐募械臄?shù)據(jù)來(lái)識(shí)別人臉。
?
識(shí)別器.load("face-trainner.yml")
?
視頻源是從USB 網(wǎng)絡(luò)攝像頭獲得的。如果您連接了多個(gè)攝像頭,請(qǐng)將 0 替換為 1 以訪(fǎng)問(wèn)輔助攝像頭。
?
cap = cv2.VideoCapture(0) #從攝像頭獲取視頻源
?
接下來(lái),我們將視頻分解為幀(圖像)并將其轉(zhuǎn)換為灰度,然后檢測(cè)圖像中的人臉。一旦檢測(cè)到人臉,我們必須像之前一樣裁剪該區(qū)域并將其單獨(dú)保存為roi_gray。 ???????????
?
ret, img = cap.read() # 將視頻分成幀 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) #convert Video frame to Greyscale faces = face_cascade.detectMultiScale(gray, scaleFactor=1.5, minNeighbors=5) #Recog . faces for (x, y, w, h) in faces: roi_gray = gray[y:y+h, x:x+w] #Convert Face to grayscale id_, conf = Recognizer.predict(roi_gray) #recognize the Face
?
變量conf告訴我們軟件識(shí)別人臉的信心。如果置信度大于 80,我們使用下面的代碼行獲取使用 ID 號(hào)的人的姓名。然后在人的臉上畫(huà)一個(gè)框,在框的頂部寫(xiě)下人的名字。
?
if conf>=80: font = cv2.FONT_HERSHEY_SIMPLEX #名稱(chēng)的字體樣式 name = labels[id_] #使用ID號(hào)從List中獲取名稱(chēng) cv2.putText(img, name, (x,y), font, 1 , (0,0,255), 2) cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)
?
最后,我們必須顯示我們剛剛分析的視頻源,然后在按下等待鍵(此處為 q)時(shí)中斷源。
?
cv2.imshow('Preview',img) #顯示視頻 if cv2.waitKey(20) & 0xFF == ord('q'): break
?
執(zhí)行此程序時(shí),請(qǐng)確保 Pi 通過(guò) HDMI 連接到顯示器。運(yùn)行程序,您會(huì)發(fā)現(xiàn)彈出一個(gè)窗口,其中包含名稱(chēng)預(yù)覽和您的視頻源。如果在視頻提要中識(shí)別出一張臉,您會(huì)在它周?chē)业揭粋€(gè)框,如果您的程序可以識(shí)別這張臉,它也會(huì)顯示該人的姓名。我們已經(jīng)訓(xùn)練了我們的程序來(lái)識(shí)別我自己和埃隆馬斯克,你可以在下面的快照中看到他們都被識(shí)別了。
曾經(jīng)值得注意的問(wèn)題是幀速率非常慢。我每 3 秒就會(huì)變得像一幀。在我的筆記本電腦上執(zhí)行相同的程序(稍作改動(dòng))給了我非常令人印象深刻的結(jié)果。也不要期望它非常準(zhǔn)確,我們的培訓(xùn)師數(shù)據(jù)非常簡(jiǎn)單,因此程序不會(huì)很可靠。您可以查看如何使用深度學(xué)習(xí)來(lái)訓(xùn)練您的數(shù)據(jù)集以提高準(zhǔn)確性。有一些方法可以提高 FPS(每秒幀數(shù)),但讓我們將其留給另一個(gè)教程。
實(shí)時(shí)人臉識(shí)別程序
#基于 face-trainner.yml 的數(shù)據(jù)檢測(cè)人臉并識(shí)別人的程序
import cv2 #用于圖像處理
import numpy as np #用于將圖像轉(zhuǎn)換為數(shù)值數(shù)組
import os #處理目錄
from PIL import Image #Pillow lib 用于處理圖像
標(biāo)簽 = [“阿斯溫斯”,“埃隆馬斯克”]
face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
識(shí)別器 = cv2.createLBPHFaceRecognizer()
識(shí)別器.load("face-trainner.yml")
cap = cv2.VideoCapture(0) #從攝像頭獲取視頻源
而(真):
ret, img = cap.read() # 將視頻分成幀
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) #將視頻幀轉(zhuǎn)換為灰度
faces = face_cascade.detectMultiScale(gray, scaleFactor=1.5, minNeighbors=5) #Recog。面孔
對(duì)于面中的 (x, y, w, h):
roi_gray = gray[y:y+h, x:x+w] #將人臉轉(zhuǎn)灰度
id_, conf = Recognizer.predict(roi_gray) #recognize the Face
如果 conf>=80:
font = cv2.FONT_HERSHEY_SIMPLEX #名稱(chēng)的字體樣式
name = labels[id_] #使用ID號(hào)從List中獲取名字
cv2.putText(img, name, (x,y), font, 1, (0,0,255), 2)
cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)
cv2.imshow('Preview',img) #顯示視頻
如果 cv2.waitKey(20) & 0xFF == ord('q'):
休息
# 一切完成后,釋放捕獲
帽釋放()
cv2.destroyAllWindows()
人臉檢測(cè)培訓(xùn)師計(jì)劃
#Program 用于訓(xùn)練人臉并創(chuàng)建 YAML 文件
import cv2 #用于圖像處理
import numpy as np #用于將圖像轉(zhuǎn)換為數(shù)值數(shù)組
import os #處理目錄
from PIL import Image #Pillow lib 用于處理圖像
face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
識(shí)別器 = cv2.createLBPHFaceRecognizer()
Face_ID = -1
pev_person_name = ""
y_ID = []
x_train = []
Face_Images = os.path.join(os.getcwd(), "Face_Images") #告訴程序我們將人臉圖像保存在哪里
打印(Face_Images)
for root, dirs, files in os.walk(Face_Images): #進(jìn)入人臉圖片目錄
for file in files: #檢查其中的每個(gè)目錄
if file.endswith("jpeg") or file.endswith("jpg") or file.endswith("png"): #對(duì)于以jpeg,jpg or png結(jié)尾的圖片文件
路徑 = os.path.join(根,文件)
person_name = os.path.basename(root)
打印(路徑,人名)
if pev_person_name!=person_name: #檢查人名是否改變
Face_ID=Face_ID+1 #如果是則增加ID計(jì)數(shù)
pev_person_name = 人名
Gery_Image = Image.open(path).convert("L") # 使用 Pillow 將圖像轉(zhuǎn)換為灰度圖
Crop_Image = Gery_Image.resize( (550,550) , Image.ANTIALIAS) #將灰度圖像裁剪為550*550(確保你的臉在所有圖像的中心)
Final_Image = np.array(Crop_Image, "uint8")
#print(Numpy_Image)
faces = face_cascade.detectMultiScale(Final_Image, scaleFactor=1.5, minNeighbors=5) #檢測(cè)所有樣本圖像中的人臉
打印(Face_ID,面孔)
對(duì)于面中的 (x,y,w,h):
roi = Final_Image[y:y+h, x:x+w] #裁剪感興趣區(qū)域(ROI)
x_train.append(roi)
y_ID.append(Face_ID)
識(shí)別器.train(x_train, np.array(y_ID)) #創(chuàng)建訓(xùn)練數(shù)據(jù)矩陣
識(shí)別器.save("face-trainner.yml") #將矩陣保存為YML文件
評(píng)論