超有趣!手把手教你使用樹莓派實現實時人臉檢測
選自hackster
作者:MJRoBot
機器之心編譯
本文介紹了如何在樹莓派上,使用 OpenCV 和 Python 完成人臉檢測項目。該項目不僅描述了識別人臉所需要的具體步驟,同時還提供了很多擴展知識。此外,該項目並不需要讀者了解詳細的人臉識別理論知識,因此初學者也能輕鬆跟著步驟實現。
項目所需設備
硬體:
樹莓派 3 Model B;
樹莓派攝像頭模塊(PiCam)。
語言和庫:
OpenCV
Python 3
步驟
本文主要講述如何使用 PiCam 實現實時人臉識別,如下圖所示:
本教程使用 OpenCV 完成,一個神奇的「開源計算機視覺庫」,並主要關注樹莓派(因此,操作系統是樹莓派系統)和 Python,但是我也在 Mac 電腦上測試了代碼,同樣運行很好。OpenCV 具備很強的計算效率,且專門用於實時應用。因此,它非常適合使用攝像頭的實時人臉識別。要創建完整的人臉識別項目,我們必須完成3個階段:
1)人臉檢測和數據收集;
2)訓練識別器;
3)人臉識別。
如下圖所示:
第1步:材料清單
主件:
樹莓派 V3:283 RMB(淘寶)
500 萬像素 1080p 感測器 OV5647 迷你攝像頭模塊:83 RMB(淘寶)
第2步:安裝OpenCV 3包
我使用的是更新了最新版樹莓派系統(Stretch)的樹莓派 V3,因此安裝 OpenCV 的最佳方式是按照 Adrian Rosebrock 寫的教程來進行:《Raspbian Stretch: Install OpenCV 3 + Python on your Raspberry Pi》。經過幾次嘗試後,我覺得Adrian的教程最好,建議按照該教程一步步來安裝。
完成上述教程之後,你應該安裝好了 OpenCV 虛擬環境,可用於在樹莓派設備上運行本次實驗。
我們來到虛擬環境,確認 OpenCV 3 已經正確安裝。
Adrian 推薦在每次打開新的終端時都運行命令行「source」,以確保系統變數都得到正確設置。
source ~/.profile
然後,我們進入虛擬環境:
workon cv
如果你看到 (cv) 出現在提示符之前,那麼你就進入了 cv 虛擬環境:
(cv) pi@raspberry:~$
Adrian 希望大家注意 cv Python 虛擬環境是完全獨立的,且與 Raspbian Stretch 中包含的默認 Python 版本彼此隔絕。因此,全局站點包目錄中的任意 Python 包對於 cv 虛擬環境而言都是不可用的。類似地,cv 站點包中的任意 Python 包對於全局 Python 包安裝也都是不可用的。
現在,進入 Python 解釋器:
python
確認你正在運行3.5(或以上)版本。
在解釋器內部(將出現>>>),導入 OpenCV 庫:
importcv2
如果沒有錯誤信息,則 OpenCV 已在你的 Python 虛擬環境中正確安裝。
你還可以檢查已安裝的 OpenCV 版本:
cv2.__version__
將會出現3.3.0(或未來有可能發布更高版本)。
上面的終端截圖顯示了以上步驟。
第3步:測試攝像頭
在樹莓派上安裝 OpenCV 之後,我們測試一下,以確認攝像頭正常運轉。假設你已經在樹莓派上安裝了 PiCam。
在 IDE 中輸入下列 Python 代碼:
importnumpyasnp
importcv2
cap = cv2.VideoCapture()
cap.set(3,640)# set Width
cap.set(4,480)# set Height
while(True):
ret, frame = cap.read()
frame = cv2.flip(frame,-1)# Flip camera vertically
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
cv2.imshow("frame", frame)
cv2.imshow("gray", gray)
k = cv2.waitKey(30) &0xff
ifk ==27:# press "ESC" to quit
break
cap.release()
cv2.destroyAllWindows()
上面的代碼可捕捉PiCam生成的視頻流,用BGR顏色和灰色模式展示。
注意:我按照組裝方式垂直旋轉了攝像頭。如果你的情況並非如此,那麼注釋或刪除「flip」命令行。
你還可以從我的 GitHub 下載代碼:https://github.com/Mjrovai/OpenCV-Object-Face-Tracking/blob/master/simpleCamTest.py
輸入下面的命令行,開始執行:
python simpleCamTest.py
要完成該程序,你必須在鍵盤上按 [ESC] 鍵。在按 [ESC] 鍵之前,先滑鼠點擊視頻窗口。
上圖展示了結果。
想更多地了解 OpenCV,請查看該教程:https://pythonprogramming.net/loading-video-python-opencv-tutorial/
第4步:人臉檢測
人臉識別的最基礎任務是「人臉檢測」。你必須首先「捕捉」人臉(第 1 階段)才能在未來與捕捉到的新人臉對比時(第 3 階段)識別它。
最常見的人臉檢測方式是使用「Haar 級聯分類器」。使用基於 Haar 特徵的級聯分類器的目標檢測是 Paul Viola 和 Michael Jones 2001 年在論文《Rapid Object Detection using a Boosted Cascade of Simple Features》中提出的一種高效目標檢測方法。這種機器學習方法基於大量正面、負面圖像訓練級聯函數,然後用於檢測其他圖像中的對象。這裡,我們將用它進行人臉識別。最初,該演算法需要大量正類圖像(人臉圖像)和負類圖像(不帶人臉的圖像)來訓練分類器。然後我們需要從中提取特徵。好消息是 OpenCV 具備訓練器和檢測器。如果你想要訓練自己的對象分類器,如汽車、飛機等,你可以使用 OpenCV 創建一個。
詳情參見:https://docs.opencv.org/3.3.0/dc/d88/tutorial_traincascade.html。
如果不想創建自己的分類器,OpenCV 也包含很多預訓練分類器,可用於人臉、眼睛、笑容等的檢測。相關的 XML 文件可從該目錄下載:https://github.com/Itseez/opencv/tree/master/data/haarcascades。
下面,我們就開始用 OpenCV 創建人臉檢測器吧!
從我的 GitHub 下載文件 faceDetection.py:https://github.com/Mjrovai/OpenCV-Face-Recognition/blob/master/FaceDetection/faceDetection.py。
importnumpyasnp
importcv2
faceCascade = cv2.CascadeClassifier("Cascades/haarcascade_frontalface_default.xml")
cap = cv2.VideoCapture()
cap.set(3,640)# set Width
cap.set(4,480)# set Height
whileTrue:
ret, img = cap.read()
img = cv2.flip(img,-1)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = faceCascade.detectMultiScale(
gray,
scaleFactor=1.2,
minNeighbors=5,
minSize=(20,20)
)
for(x,y,w,h)infaces:
cv2.rectangle(img,(x,y),(x+w,y+h),(255,,),2)
roi_gray = gray[y:y+h, x:x+w]
roi_color = img[y:y+h, x:x+w]
cv2.imshow("video",img)
k = cv2.waitKey(30) &0xff
ifk ==27:# press "ESC" to quit
break
cap.release()
cv2.destroyAllWindows()
使用 Python 和 OpenCV 執行人臉檢測,上面的幾行代碼就足夠了。注意下面的代碼:
faceCascade = cv2.CascadeClassifier("Cascades/haarcascade_frontalface_default.xml")
這行代碼可以載入「分類器」(必須在項目文件夾下面的 Cascades/目錄中)。然後,我們在在循環內部調用攝像頭,並以 grayscale 模式載入我們的輸入視頻。現在,我們必須調用分類器函數,向其輸入一些非常重要的參數,如比例因子、鄰近數和人臉檢測的最小尺寸。
faces = faceCascade.detectMultiScale(
gray,
scaleFactor=1.2,
minNeighbors=5,
minSize=(20,20)
)
其中:
gray 表示輸入 grayscale 圖像。
scaleFactor 表示每個圖像縮減的比例大小。
minNeighbors 表示每個備選矩形框具備的鄰近數量。數字越大,假正類越少。
minSize 表示人臉識別的最小矩形大小。
該函數將檢測圖像中的人臉。接下來,我們必須「標記」圖像中的人臉,比如,用藍色矩形。使用下列代碼完成這一步:
for(x,y,w,h)infaces:
cv2.rectangle(img,(x,y),(x+w,y+h),(255,,),2)
roi_gray = gray[y:y+h, x:x+w]
roi_color = img[y:y+h, x:x+w]
如果已經標記好人臉,則函數將檢測到的人臉的位置返回為一個矩形,左上角 (x,y),w 表示寬度,h 表示高度 ==> (x,y,w,h)。詳見下圖。
得到這些位置信息後,我們可以為人臉創建一個「感興趣區域」(繪製矩形),用 imshow() 函數呈現結果。使用樹莓派終端,在你的 Python 環境中運行上面的 Python 腳本:
python faceDetection.py
結果如下:
你也可以加入諸如「眼睛檢測」甚至「微笑檢測」這樣的檢測器。在那些用例中,你需要把分類器函數和矩形框內加入原有的面部識別區域中,因為在區域外進行識別沒有意義。
注意,在樹莓派上,分類方法(HaarCascades)會消耗大量算力,所以在同一代碼中使用多個分類器將會顯著減慢處理速度。在台式機上運行這些演算法則非常容易。
在我的 GitHub上你可以看到另外的例子:
faceEyeDetection.py
faceSmileDetection.py
faceSmileEyeDetection.py
在下圖中,你可以看到我們的結果:
要想深入理解面部識別,可以參考這一教程:https://pythonprogramming.net/haar-cascade-face-eye-detection-python-opencv-tutorial/
第5步:收集數據
我推薦各位讀者可以查看以下兩個關於人臉識別的教程:
使用 OpenCV 和 Python 從頭實現人臉識別:https://www.superdatascience.com/opencv-face-recognition/
理解人臉識別:https://thecodacus.com/category/opencv/face-recognition/
現在,我們項目的第一步是創建一個簡單的數據集,該數據集將儲存每張人臉的 ID 和一組用於人臉檢測的灰度圖。
因此,以下命令行將為我們的項目創建一個目錄,目錄名可以如以下為 FacialRecognitionProject 或其它:
mkdir FacialRecognitionProject
在該目錄中,除了我們為項目創建的 3 個 Python 腳本外,我們還需要儲存人臉分類器。我們可以從 GitHub 中下載:haarcascade_frontalface_default.xml。
下一步需要創建一個子目錄「dtatset」,並用它來儲存人臉樣本:
mkdir dataset
然後從我的 GitHub 中下載代碼 01_face_dataset.py。
importcv2
importos
cam = cv2.VideoCapture()
cam.set(3,640)# set video width
cam.set(4,480)# set video height
face_detector = cv2.CascadeClassifier("haarcascade_frontalface_default.xml")
# For each person, enter one numeric face id
face_id = input("
enter user id end press ==> ")
print("
[INFO] Initializing face capture. Look the camera and wait ...")
# Initialize individual sampling face count
count =
while(True):
ret, img = cam.read()
img = cv2.flip(img,-1)# flip video image vertically
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = face_detector.detectMultiScale(gray,1.3,5)
for(x,y,w,h)infaces:
cv2.rectangle(img, (x,y), (x+w,y+h), (255,,),2)
count +=1
# Save the captured image into the datasets folder
cv2.imwrite("dataset/User."+ str(face_id) +"."+ str(count) +".jpg", gray[y:y+h,x:x+w])
cv2.imshow("image", img)
k = cv2.waitKey(100) &0xff# Press "ESC" for exiting video
ifk ==27:
break
elifcount >=30:# Take 30 face sample and stop video
break
# Do a bit of cleanup
print("
[INFO] Exiting Program and cleanup stuff")
cam.release()
cv2.destroyAllWindows()
上述的代碼和人臉識別的代碼非常像,我們只是添加了一個「input command」來捕捉用戶 ID(整數)。
face_id = input("
enter user id end press ==> ")
對於每一個捕捉的幀,我們應該在「dataset」目錄中保存為文檔:
cv2.imwrite("dataset/User."+ str(face_id) +"."+ str(count) +".jpg", gray[y:y+h,x:x+w])
對於保存上述文件,我們需要導入「os」庫,每一個文件的名字都服從以下結構:
例如,對於 face_id = 1 的用戶,dataset/ 目錄下的第四個樣本文件名可能為:
User.1.4.jpg
在我的樹莓派中,該圖像可以打開為:
在我的代碼中,我從每一個 ID 捕捉 30 個樣本,我們能在最後一個條件語句中修改抽取的樣本數。如果我們希望識別新的用戶或修改已存在用戶的相片,我們就必須以上腳本。
第六步:訓練
在第二階段中,我們需要從數據集中抽取所有的用戶數據,並訓練 OpenCV 識別器,這一過程可由特定的 OpenCV 函數直接完成。這一步將在「trainer/」目錄中保存為.yml 文件。
所以,下面開始創建子目錄以儲存訓練數據:
mkdir trainer
從我的 GitHub 中下載第二個 Python 腳本:02_face_training.py。
importcv2
importnumpyasnp
fromPILimportImage
importos
# Path for face image database
path ="dataset"
recognizer = cv2.face.LBPHFaceRecognizer_create()
detector = cv2.CascadeClassifier("haarcascade_frontalface_default.xml");
# function to get the images and label data
defgetImagesAndLabels(path):
imagePaths = [os.path.join(path,f)forfinos.listdir(path)]
faceSamples=[]
ids = []
forimagePathinimagePaths:
PIL_img = Image.open(imagePath).convert("L")# convert it to grayscale
img_numpy = np.array(PIL_img,"uint8")
id = int(os.path.split(imagePath)[-1].split(".")[1])
faces = detector.detectMultiScale(img_numpy)
for(x,y,w,h)infaces:
faceSamples.append(img_numpy[y:y+h,x:x+w])
ids.append(id)
returnfaceSamples,ids
print("
[INFO] Training faces. It will take a few seconds. Wait ...")
faces,ids = getImagesAndLabels(path)
recognizer.train(faces, np.array(ids))
# Save the model into trainer/trainer.yml
recognizer.write("trainer/trainer.yml")# recognizer.save() worked on Mac, but not on Pi
# Print the numer of faces trained and end program
print("
[INFO] faces trained. Exiting Program".format(len(np.unique(ids))))
確定在 Rpi 中已經安裝了 PIL 庫,如果沒有的話,在終端運行以下命令:
pip install pillow
我們將使用 LBPH(LOCAL BINARY PATTERNS HISTOGRAMS)人臉識別器,它由 OpenCV 提供:
recognizer = cv2.face.LBPHFaceRecognizer_create()
函數「getImagesAndLabels (path)」將抽取所有在目錄「dataset/」中的照片,並返回 2 個數組:「Ids」和「faces」。通過將這些數組作為輸入,我們就可以訓練識別器。
recognizer.train(faces, ids)
在訓練過後,文件「trainer.yml」將保存在我們前面定義的 trainer 目錄下。此外,我們還在最後使用了 print 函數以確認已經訓練的用戶面部數量。
第7步:識別器
這是該項目的最後階段。這裡,我們將通過攝像頭捕捉一個新人臉,如果這個人的面孔之前被捕捉和訓練過,我們的識別器將會返回其預測的 id 和索引,並展示識別器對於該判斷有多大的信心。
讓我們從 GitHub 03_face_recognition.py 上下載第三階段的 python 腳本。
importcv2
importnumpyasnp
importos
recognizer = cv2.face.LBPHFaceRecognizer_create()
recognizer.read("trainer/trainer.yml")
cascadePath ="haarcascade_frontalface_default.xml"
faceCascade = cv2.CascadeClassifier(cascadePath);
font = cv2.FONT_HERSHEY_SIMPLEX
#iniciate id counter
id =
# names related to ids: example ==> Marcelo: id=1, etc
names = ["None","Marcelo","Paula","Ilza","Z","W"]
# Initialize and start realtime video capture
cam = cv2.VideoCapture()
cam.set(3,640)# set video widht
cam.set(4,480)# set video height
# Define min window size to be recognized as a face
minW =0.1*cam.get(3)
minH =0.1*cam.get(4)
whileTrue:
ret, img =cam.read()
img = cv2.flip(img,-1)# Flip vertically
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
faces = faceCascade.detectMultiScale(
gray,
scaleFactor =1.2,
minNeighbors =5,
minSize = (int(minW), int(minH)),
)
for(x,y,w,h)infaces:
cv2.rectangle(img, (x,y), (x+w,y+h), (,255,),2)
id, confidence = recognizer.predict(gray[y:y+h,x:x+w])
# Check if confidence is less them 100 ==> "0" is perfect match
if(confidence
id = names[id]
confidence =" %".format(round(100- confidence))
else:
id ="unknown"
confidence =" %".format(round(100- confidence))
cv2.putText(img, str(id), (x+5,y-5), font,1, (255,255,255),2)
cv2.putText(img, str(confidence), (x+5,y+h-5), font,1, (255,255,),1)
cv2.imshow("camera",img)
k = cv2.waitKey(10) &0xff# Press "ESC" for exiting video
ifk ==27:
break
# Do a bit of cleanup
print("
[INFO] Exiting Program and cleanup stuff")
cam.release()
cv2.destroyAllWindows()
這裡我們包含了一個新數組,因此我們將會展示「名稱」,而不是編號的 id:
names = ["None","Marcelo","Paula","Ilza","Z","W"]
所以,如上所示的列表,Marcelo 的 ID 或索引為 1,Paula 的 ID 等於 2。
下一步,我們將檢測一張人臉,正如我們在之前的 haasCascade 分類器中所做的那樣。
id, confidence = recognizer.predict(gray portion of the face)
recognizer.predict () 將把待分析人臉的已捕捉部分作為一個參數,並返回其可能的所有者,指示其 id 以及識別器與這一匹配相關的置信度。
注意,如果匹配是完美的,置信度指數將返回「零」。
最後,如果識別器可以預測人臉,我們將在圖像上放置一個文本,帶有可能的 id,以及匹配是否正確的概率(概率=100 - 置信度指數)。如果沒有,則把「未知」的標籤放在人臉上。
下面是這一結果的圖片:
在這張圖像上,我展示了一些由該項目完成的測試,其中我也使用圖像驗證識別器是否有效。
第 8 步:結語
我希望該項目能幫助其他人發現更好玩的項目,也希望有助於各位讀者實現自己的人臉識別應用。
更多詳細的代碼請查看GitHub地址:https://github.com/Mjrovai/OpenCV-Face-Recognition
本文為機器之心編譯,轉載請聯繫本公眾號獲得授權。
?------------------------------------------------
※中科大潘建偉團隊在光量子處理器上成功實現拓撲數據分析
※蘋果音箱HomePod最新測評:音質沒得說 智能?不存在的
TAG:機器之心 |