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