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