本文我將如何在樹莓派上,使用 OpenCV 和 Python 完成人臉檢測項目。不僅可以實時的檢測,還可以進行學習、訓練和檢測。
項目所需設備
硬件:
樹莓派4b
樹莓派攝像頭模塊(Camrea V2)
語言和庫:
OpenCV
Python 3
環境配置在我上篇博客已經介紹的很詳細了,可以進行參考一下。
首先啟動樹莓派攝像頭模塊。
運行樹莓派配置工具來激活攝像頭模塊:
$ sudo raspi-config
進入Interfacing Options然后就可以啟動你想要的功能,移動光標至菜單中的 "Enable Camera(啟用攝像頭)",將其設為Enable(啟用狀態)。完成之后重啟樹莓派。
在重啟完樹莓派后,我們就可以使用Pi Camera v2了。要用它來拍攝照片的話,可以從命令行運行raspistill:raspistill -o test.jpg
這樣的話就啟動了,注意照片的文件名可以自己任意設置。
下載需要的庫
pip install pillow
接下來開始項目開始了
本教程使用 OpenCV 完成,一個神奇的「開源計算機視覺庫」,並主要關注樹莓派(因此,操作系統是樹莓派系統)和 Python,但是我也在 Mac 電腦上測試了代碼,同樣運行很好。OpenCV 具備很強的計算效率,且專門用於實時應用。因此,它非常適合使用攝像頭的實時人臉識別。要創建完整的人臉識別項目,我們必須完成3個階段:
1)人臉檢測和數據收集;
2)訓練識別器;
3)人臉識別。
一.我們項目的第一步是創建一個簡單的數據集,該數據集將儲存每張人臉的 ID 和一組用於人臉檢測的灰度圖。
因此,以下命令行將為我們的項目創建一個目錄,目錄名可以如以下為 FaceProject
mkdir FaceProject
在該目錄中,除了我們為項目創建的 3 個 Python 腳本外,我們還需要儲存人臉分類器。我們可以從 GitHub 中下載:haarcascade_frontalface_default.xml
下一步需要創建一個子目錄「dtatset」,並用它來儲存人臉樣本:
mkdir dataset
收集數據的代碼如下:face_dataset_01.py
1 import cv2 2 import os 3 4 cam = cv2.VideoCapture(0) 5 cam.set(3, 640) # set video width 6 cam.set(4, 480) # set video height 7 8 face_detector = cv2.CascadeClassifier('haarcascade_frontalface_default.xml') 9 10 # For each person, enter one numeric face id 11 face_id = input('\n enter user id end press <return> ==> ') 12 13 print("\n [INFO] Initializing face capture. Look the camera and wait ...") 14 # Initialize individual sampling face count 15 count = 0 16 17 while(True): 18 ret, img = cam.read() 19 img = cv2.flip(img, -1) # flip video image vertically 20 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 21 faces = face_detector.detectMultiScale(gray, 1.3, 5) 22 23 for (x,y,w,h) in faces: 24 cv2.rectangle(img, (x,y), (x+w,y+h), (255,0,0), 2) 25 count += 1 26 27 # Save the captured image into the datasets folder 28 cv2.imwrite("dataset/User." + str(face_id) + '.' + str(count) + ".jpg", gray[y:y+h,x:x+w]) 29 30 cv2.imshow('image', img) 31 32 k = cv2.waitKey(100) & 0xff # Press 'ESC' for exiting video 33 if k == 27: 34 break 35 elif count >= 30: # Take 30 face sample and stop video 36 break 37 38 # Do a bit of cleanup 39 print("\n [INFO] Exiting Program and cleanup stuff") 40 cam.release() 41 cv2.destroyAllWindows()
運行命令:python face_dataset_01.py
我是以第一個人的ID唯一開始的,收集測試人的30張灰度圖片,存到dataset文件中,可以自己進行查看。
在我的代碼中,我從每一個 ID 捕捉 30 個樣本,我們能在最后一個條件語句中修改抽取的樣本數。如果我們希望識別新的用戶或修改已存在用戶的相片,可以自己進行添加。
二.開始訓練數據
下面開始創建子目錄以儲存訓練數據:
mkdir trainer
在第二階段中,我們需要從數據集中抽取所有的用戶數據,並訓練 OpenCV 識別器,這一過程可由特定的 OpenCV 函數直接完成。這一步將在「trainer/」目錄中保存為trainer.yml 文件。
訓練代碼:face_training_02.py
1 import numpy as np 2 from PIL import Image 3 import os 4 5 # Path for face image database 6 path = 'dataset' 7 8 recognizer = cv2.face.LBPHFaceRecognizer_create() 9 detector = cv2.CascadeClassifier("haarcascade_frontalface_default.xml"); 10 11 # function to get the images and label data 12 def getImagesAndLabels(path): 13 imagePaths = [os.path.join(path,f) for f in os.listdir(path)] 14 faceSamples=[] 15 ids = [] 16 for imagePath in imagePaths: 17 PIL_img = Image.open(imagePath).convert('L') # convert it to grayscale 18 img_numpy = np.array(PIL_img,'uint8') 19 id = int(os.path.split(imagePath)[-1].split(".")[1]) 20 faces = detector.detectMultiScale(img_numpy) 21 for (x,y,w,h) in faces: 22 faceSamples.append(img_numpy[y:y+h,x:x+w]) 23 ids.append(id) 24 return faceSamples,ids 25 26 print ("\n [INFO] Training faces. It will take a few seconds. Wait ...") 27 faces,ids = getImagesAndLabels(path) 28 recognizer.train(faces, np.array(ids)) 29 30 # Save the model into trainer/trainer.yml 31 recognizer.write('trainer/trainer.yml') # recognizer.save() worked on Mac, but not on Pi 32 33 # Print the numer of faces trained and end program 34 print("\n [INFO] {0} faces trained. Exiting Program".format(len(np.unique(ids))))
運行命令:python face_training_02.py
數據在被訓練之后,文件「trainer.yml」將保存在我們前面定義的 trainer 目錄下
三.人臉識別
我們將通過攝像頭捕捉一個新人臉,如果這個人的面孔之前被捕捉和訓練過,我們的識別器將會返回其預測的 id 和索引。
代碼如下:face_recognition_03.py
1 import cv2 2 import numpy as np 3 import os 4 5 recognizer = cv2.face.LBPHFaceRecognizer_create() 6 recognizer.read('trainer/trainer.yml') 7 cascadePath = "haarcascade_frontalface_default.xml" 8 faceCascade = cv2.CascadeClassifier(cascadePath); 9 10 font = cv2.FONT_HERSHEY_SIMPLEX 11 12 #iniciate id counter 13 id = 0 14 15 # names related to ids: example ==> Marcelo: id=1, etc 16 names = ['None', 'tanshengjang', 'Paula', 'Ilza', 'Z', 'W'] 17 18 # Initialize and start realtime video capture 19 cam = cv2.VideoCapture(0) 20 cam.set(3, 640) # set video widht 21 cam.set(4, 480) # set video height 22 23 # Define min window size to be recognized as a face 24 minW = 0.1*cam.get(3) 25 minH = 0.1*cam.get(4) 26 27 while True: 28 ret, img =cam.read() 29 img = cv2.flip(img, -1) # Flip vertically 30 gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) 31 32 faces = faceCascade.detectMultiScale( 33 gray, 34 scaleFactor = 1.2, 35 minNeighbors = 5, 36 minSize = (int(minW), int(minH)), 37 ) 38 39 for(x,y,w,h) in faces: 40 cv2.rectangle(img, (x,y), (x+w,y+h), (0,255,0), 2) 41 id, confidence = recognizer.predict(gray[y:y+h,x:x+w]) 42 43 # Check if confidence is less them 100 ==> "0" is perfect match 44 if (confidence < 100): 45 id = names[id] 46 confidence = " {0}%".format(round(100 - confidence)) 47 else: 48 id = "unknown" 49 confidence = " {0}%".format(round(100 - confidence)) 50 51 cv2.putText(img, str(id), (x+5,y-5), font, 1, (255,255,255), 2) 52 cv2.putText(img, str(confidence), (x+5,y+h-5), font, 1, (255,255,0), 1) 53 54 cv2.imshow('camera',img) 55 56 k = cv2.waitKey(10) & 0xff # Press 'ESC' for exiting video 57 if k == 27: 58 break 59 60 # Do a bit of cleanup 61 print("\n [INFO] Exiting Program and cleanup stuff") 62 cam.release() 63 cv2.destroyAllWindows()
運行命令:face_recognition_03.py
這里我們包含了一個新數組,因此我們將會展示「名稱」,而不是編號的 id:
names = ['None', 'tanshengjiang', 'Paula', 'Ilza', 'Z', 'W']