在本指南中,我們將教您如何使用OpenCV和面部識別庫(兩個出色的開源項目)設置樹莓派來檢測和識別面部。在這個設置中,所有的數據和處理都將在Pi上本地執行,這意味著您的所有面部和數據都不會離開Pi本身。
像面部識別這樣的計算機視覺任務對初學者來說可能有點嚇人,但由于許多人的努力,這些任務已經被簡化了。我們將從安裝所需的庫和包開始,然后運行3段代碼。首先將使用Pi來拍攝照片,然后我們將使用這些照片作為數據集來訓練人臉識別模型,最后我們將運行人臉識別代碼本身。
如果你對計算機視覺,目標檢測和姿態估計感興趣,也可以考慮查看以下內容:
在樹莓派5上使用YOLO進行物體和動物識別-入門指南
在樹莓派5上開啟YOLO姿態估計識別之旅!
如何在樹莓派 AI HAT+上進行YOLO目標檢測?
如何在樹莓派 AI HAT+上進行YOLO姿態估計?
讓我們開始吧!
目錄:
所需材料
硬件組裝
安裝樹莓派操作系統
設置虛擬環境并安裝庫
拍照并訓練模型
運行人臉識別
硬件控制及后續步驟
致謝
代碼下載
附錄:代碼解析
所需材料
要跟隨本指南操作,您需要:
樹莓派5 - 當使用基于150張圖像訓練的模型時,我們發現它大約需要1.3GB的RAM。因此,2GB的樹莓派可能也能用,但4GB或8GB的型號會更穩妥。本指南也適用于樹莓派4,但性能會慢一倍。
樹莓派攝像頭 - 我們使用的是攝像頭模塊V3
轉接線 - 如果您使用的是樹莓派5,它配備的是不同尺寸的CSI攝像頭線,而您的攝像頭可能配備的是較舊的較粗的線,因此值得仔細檢查一下。攝像頭模塊V3肯定需要一條轉接線
散熱方案 - 本項目處理量較大,因此需要適當的散熱方法。對于我們的樹莓派5,我們使用的是主動散熱器。
Micro SD卡 - 至少16GB容量
顯示器和Micro-HDMI轉HDMI線
鼠標和鍵盤
*所需物品可以直接聯系我們進行購買。
硬件組裝
在硬件組裝方面,這里相當簡單。將線纜較粗的一端連接到攝像頭,較細的一端連接到樹莓派5。這些連接器上有一個標簽 - 將其抬起,然后將線纜插入插槽。確保線纜放置整齊且方正,然后將標簽推回原位以固定線纜。

請注意,這些連接器只能以一個方向插入,且它們可能比較脆弱,因此請避免過度彎曲(稍微彎曲一點沒問題)。
安裝Bookworm操作系統
首先,我們需要將樹莓派操作系統安裝到Micro SD卡上。使用樹莓派成像工具,選擇樹莓派5作為設備,選擇Raspberry Pi OS(64位)作為操作系統,并選擇您的microSD卡作為存儲設備。

注意:將樹莓派操作系統安裝到MicroSD卡上將會清除卡上的所有數據。
此過程可能需要幾分鐘時間來下載操作系統并安裝。安裝完成后,將其插入樹莓派并啟動。您的樹莓派將進行首次安裝,請確保將其連接到互聯網。
設置虛擬環境并安裝庫
隨著2023年Bookworm操作系統的推出,我們現在需要使用虛擬環境(或venv)。這些只是隔離的虛擬空間,我們可以使用它們來運行項目,而不會破壞樹莓派操作系統的其余部分和我們的包 - 換句話說,我們可以在這里隨心所欲地操作,而不會損壞樹莓派操作系統的其余部分。這是一個需要學習的額外部分,但它非常簡單。

要創建虛擬環境,請打開一個新的終端窗口并輸入:
python3 -m venv--system-site-packagesface_rec
這將創建一個名為“face_rec”的新虛擬環境。您可以在home/pi下找到這個虛擬環境的文件夾,它將被命名為“face_rec”。
創建venv后,通過輸入以下命令進入它:
執行此操作后,您將在綠色文本的左側看到虛擬環境的名稱 - 這意味著我們正在其中正確工作。如果您需要重新進入此環境(例如,如果您關閉了終端窗口,您將退出環境),只需再次輸入上面的source命令即可。

現在,我們正在虛擬環境中工作,可以開始安裝所需的包了。首先,我們將通過輸入以下命令來確保我們的包列表和樹莓派是最新的:
sudo aptupdatesudo aptfull-upgrade
然后輸入以下命令安裝OpenCV:
pipinstall opencv-python
我們還將安裝一個我們需要的工具Imutils:
pipinstall imutils
以及一個名為cmake的工具(在提示時按y鍵):
sudoapt install cmake
然后我們將安裝人臉識別庫:
pipinstall face-recognition
此安裝過程可能需要10到30分鐘,因此在此期間請喝杯茶休息一下。

我們還有一件事要做,那就是設置Thonny以使用我們剛剛創建的虛擬環境。Thonny是我們將運行所有代碼的程序,我們需要讓它從同一個venv中運行,以便它可以訪問我們安裝的庫。
首次打開Thonny時,它可能處于簡化模式,您將在右上角看到“切換到常規模式”。如果存在此選項,請點擊它并關閉Thonny以重新啟動。

現在,通過選擇“運行”>“配置解釋器”進入解釋器選項菜單。在Python可執行文件選項下,有一個帶有三個點的按鈕。選擇它并導航到我們剛剛創建的虛擬環境中的Python可執行文件。

它位于home/pi/face_rec/bin下,在此文件中,您需要選擇名為“python3”的文件。點擊確定,您現在將在此venv中工作。
無論何時打開Thonny,它現在都將自動在此環境中運行。您可以通過從同一解釋器選項菜單中的Python可執行文件下的下拉菜單中選擇它來更改您正在使用的環境。如果您希望退出虛擬環境,請選擇“bin/python3”選項。
拍照并訓練模型
在開始識別人臉之前,我們需要使用我們希望它識別的人臉來訓練模型。首先下載項目文件夾,其中包含運行此項目所需的所有內容。解壓并將其放置在易于訪問的位置(我們只是將其放在了桌面上)。
在此文件夾中,您將看到我們將使用的三個Python腳本以及一個名為dataset的文件夾。這是我們將用我們希望訓練模型的圖像填充的文件夾。在Thonny中打開名為image_capture.py的Python腳本 - 您可能需要右鍵單擊并選擇Thonny,因為它通常不是默認的Python編輯器。我們不會詳細剖析這段代碼的工作原理,但我們只需要知道它會拍照并將它們放置在我們需要的正確文件結構中。
在腳本的頂部,您將看到以下行:
# Change this to the name of the person you're photographingPERSON_NAME="John Smith"
當您拍攝某人的面部照片時,這將是分配給該人的名字。請注意,它是區分大小寫的,因此John Smith和john smith將是兩個人。這里的一個好做法可能是只使用小寫字母,以免意外訓練同一個人兩次。
因此,請繼續將其設置為您要訓練的第一個人名字,然后點擊綠色播放按鈕運行它。將彈出一個新窗口顯示攝像頭畫面。調整好位置后按空格鍵拍照!您可以在此窗口中拍攝任意數量的照片,完成后按“Q”鍵退出。

選擇用于訓練模型的照片數量將取決于您的項目。對于大多數應用來說,一張清晰的人臉正對攝像頭且光線良好的照片通常就足夠了,但再多幾張不同角度的人臉照片也無妨。
如果您現在查看dataset文件夾,您將看到此過程已創建了一個以代碼開頭幾行中設置的人名為名稱的新文件夾,并且此文件夾內還將包含在此過程中拍攝的所有圖像。這就是我們需要訓練模型的結構 - 一個包含我們希望識別的人臉名稱或ID的文件夾,以及我們希望使用的圖像。如果您想使用現有的照片,可以在dataset中創建一個文件夾,將文件夾名稱設置為這將識別的人,然后將照片放入其中。
一旦您擁有了所有希望識別的人的照片文件,請在thonny中打開名為model_training.py的腳本。如果您運行此腳本,它將使用所有這些照片來訓練我們將在下一步中使用的模型,并且您可以在shell中看到此過程的實時進度。根據您訓練它的圖像數量,此過程可能需要幾秒到幾分鐘的時間。
訓練完成后,您將看到一個完成消息,并且它將創建一個名為“encodings.pickle”的文件 - 這是我們訓練好的模型。

運行人臉識別
現在,我們終于準備好運行人臉識別了。在Thonny中打開facial_recognition.py腳本并運行它。幾秒鐘后,將出現攝像頭畫面,如果一切正常,它應該能夠通過在人臉周圍繪制一個框并標注名字來識別人臉。它只能檢測到您訓練過的人臉,如果它檢測到一個不在數據集中的人臉,它將只是將其標記為“未知”。您還可以在右上角看到幀處理速度(FPS)。
您還應該發現它相當準確,即使對于移動和模糊的對象也是如此 - 搖搖頭看看它是否仍然能識別您。戴上一副太陽鏡,它應該仍然能夠識別您。不過,也有一些方法可以欺騙這個系統,如果您將頭傾斜超過45度,它可能根本無法識別您,如果您部分遮擋面部,它也將難以檢測到您。

我們可以在代碼中調整兩個變量來增加FPS或處理能力,它們是攝像頭的輸入分辨率和一個在處理攝像頭畫面時改變分辨率的縮放器。
在代碼的開頭部分,您將找到以特定分辨率初始化攝像頭的行。默認情況下,它是1920 x 1080像素,我們可以將其設置為幾乎任何大小,只要它不超過攝像頭的功能范圍即可。
picam2.configure(picam2.create_preview_configuration(main={"format": 'XRGB8888',"size": (1920,1080)}))
再往下一點,您將找到一個名為“cv_scaler”的變量。這是一個將攝像頭分辨率從我們初始化時的分辨率進行縮放的變量。這個數字必須是一個整數 - 因此不能有小數點。
cv_scaler=4# this has to be a whole number
我們輸入到facial_recognition庫的分辨率會影響其性能,我們可以調整這兩個變量來改變分辨率,因此讓我們快速看一下如何首先使用這兩個變量來改變分辨率。代碼獲取攝像頭的分辨率并將其除以cv_scaler。以下是一些示例:
如果分辨率設置為1920x1080,且cv_scaler = 10,則處理后的分辨率將為192x108
如果分辨率設置為1920x1080,且cv_scaler = 4,則處理后的分辨率將為480x270
如果分辨率設置為480x270且cv_scaler = 1,則處理后的分辨率將為480x270
請注意,在后兩個示例中,處理分辨率為480x270,雖然它們將提供相同的FPS和處理能力,但最后一個的預覽窗口將較小且分辨率較低,因為那是我們初始化攝像頭畫面的大小。最好將您的分辨率設置為較大的尺寸,如1920x1080或1280x720,并更改cv_scaler來降低分辨率。
現在我們知道如何降低分辨率了,讓我們看看對性能的影響。下圖展示了兩種不同分辨率的處理情況。兩者都將攝像頭初始化為1920x1080,但左圖的cv_scaler = 1,結果為0.5 FPS,而右圖的cv_scaler = 10,結果約為5 FPS。圖像中還顯示了它們能夠識別人臉的最大距離,左圖是從我們大型工作室房間的另一端,而右圖只有約一米遠。這可能只是心理作用,但我們認為較高的分辨率也可能更準確地捕捉到模糊的對象 - 但差別不大。

硬件控制及后續步驟
到目前為止,我們的設置可以識別人臉、在其周圍繪制一個框并標注名字。讓我們更進一步,使用名為facial_recognition_hardware.py的腳本對其做些其他事情。此腳本有一些額外的添加,允許我們控制樹莓派的GPIO引腳。在腳本的頂部,您將找到一個授權名字列表,當檢測到這些名字時,將打開樹莓派的14號引腳:
authorized_names= ["john","alice","bob"] # Replace with your actual names
如果您希望向此列表添加或更改名字,請將名字放在括號中并用逗號分隔。請注意,這也是區分大小寫的,如果您將所有訓練名字都保持小寫,請在此處也保持這樣做。
在process_frame函數中,我們有以下代碼段:
# Control the GPIO pin based on face detection ifauthorized_face_detected: output.on() # TurnonPin else: output.off() # TurnoffPin
這是這個新腳本的核心部分,如果檢測到授權人臉,它將打開14號引腳,如果沒有檢測到人臉,它將關閉該引腳。如果您想在此之外做其他事情,這是您可以添加代碼的地方。
在視頻指南中,我們連接了一個由電磁閥驅動的門鎖和一個繼電器,設置了授權名字列表,并在識別人臉時偽“解鎖了門”。您還會注意到另一個添加,即我們在授權名單上的人臉下方添加了文字,說明此人是授權的。

雖然這是一個具體的示例,但它可以修改為執行幾乎任何任務,因為我們有一個簡單的結構 - 如果檢測到人臉,則執行某操作,否則執行其他操作。我們可以使用此邏輯來控制一組RGB LED燈,或控制一個伺服電機,或打開一個電機。(另外,如果您想學習如何將電磁閥連接到樹莓派,我們有相關指南)
它也不一定非要控制硬件,我們可以選擇發送電子郵件,或通過藍牙發送通知,或任何其他基于軟件的自動化。雖然我們沒有明確的指南介紹這些,但您應該可以將我們的演示腳本粘貼到像ChatGPT或Claude這樣的LLM中,并讓它們幫助您編寫所需的代碼。
致謝
像這樣的項目之所以成為可能,要歸功于眾多人員將開源項目帶給大眾所做出的不可思議的工作。我們主要想向OpenCV和人臉識別庫團隊表示衷心的感謝,感謝他們創建了這些項目。我們還要感謝Caroline Dunn開發了大量利用pickle模型的代碼。
代碼下載
您可以在此zip文件中找到本指南中運行的所有腳本。
https://core-electronics.com.au/attachments/uploads/facial-recognition-updated.zip
附錄:代碼解析
對于那些希望了解這段代碼內部工作原理的人來說,讓我們快速瀏覽一下并看看幕后發生了什么。這并不是了解發生了什么的必要條件,但對于那些想要了解的人來說只是一個額外的內容。
與往常一樣,我們的代碼從導入所需的庫開始,包括我們之前安裝的OpenCV和人臉識別庫:
importface_recognitionimportcv2importnumpyasnpfrompicamera2importPicamera2importtimeimportpickle
然后我們加載我們創建的pickle模型并將其解包為faces和names。
print("[INFO] loading encodings...")withopen("encodings.pickle","rb")asf: data= pickle.loads(f.read())known_face_encodings =data["encodings"]known_face_names =data["names"]
使用Picamera 2,我們然后以指定的分辨率初始化攝像頭:
picam2= Picamera2()picam2.configure(picam2.create_preview_configuration(main={"format": 'XRGB8888',"size": (1920,1080)}))picam2.start()
然后我們初始化一堆將在代碼其余部分使用的變量。這是我們可以更改cv_scaler的地方:
cv_scaler=4#
face_locations= []face_encodings= []face_names= []frame_count=0start_time= time.time()fps=0
接下來,我們創建第一個函數,該函數接收一幀并從中獲取識別數據。它首先使用cv_scaler將我們輸入的幀縮小到較低的分辨率。然后,根據庫的需要將其從BGR轉換為RGB:
defprocess_frame(frame): globalface_locations, face_encodings, face_names
# Resize the frame using cv_scaler to increase performance (less pixels processed, less time spent) resized_frame= cv2.resize(frame, (0,0), fx=(1/cv_scaler), fy=(1/cv_scaler))
# Convert the image from BGR to RGB colour space, the facial recognition library uses RGB, OpenCV uses BGR rgb_resized_frame= cv2.cvtColor(resized_frame, cv2.COLOR_BGR2RGB)
然后我們將縮小后的幀輸入到人臉識別庫中,并獲取人臉的位置和編碼。
face_locations= face_recognition.face_locations(rgb_resized_frame) face_encodings= face_recognition.face_encodings(rgb_resized_frame, face_locations, model='large')
之后,我們使用一個for循環遍歷圖像中的所有人臉,并查看編碼是否與我們訓練模型中的任何編碼匹配。
face_names=[] forface_encoding in face_encodings: # See if the face is a match for the known face(s) matches= face_recognition.compare_faces(known_face_encodings, face_encoding) name="Unknown"
# Use the known face with the smallest distance to the new face face_distances= face_recognition.face_distance(known_face_encodings, face_encoding) best_match_index= np.argmin(face_distances) ifmatches[best_match_index]: name= known_face_names[best_match_index] face_names.append(name)
returnframe
然后我們創建另一個函數,該函數將接收幀并在其周圍繪制框,以及用識別出的名字標注它。for循環意味著它將遍歷所有識別出的人臉。它使用頂部、右側、底部和左側坐標(我們在上一個函數中通過face_locations找到的)在識別出的人臉周圍繪制一個框。但在使用它之前,我們必須按cv_scaler進行縮放,否則它不會在我們的攝像頭預覽上繪制在正確的位置(處理是在縮小后的幀上進行的,因此我們必須將坐標放大以匹配我們的攝像頭預覽):
defdraw_results(frame): # Display the results for(top, right, bottom, left), nameinzip(face_locations, face_names): # Scale back up face locations since the frame we detected in was scaled top *= cv_scaler right *= cv_scaler bottom *= cv_scaler left *= cv_scaler
然后我們使用OpenCV提供的工具來實際繪制這些東西。我們首先在人臉周圍繪制一個藍色的空矩形,線寬為3,然后在這個框上繪制一個實心矩形,最后將名字放在這個實心框上。
# Draw a box around the face cv2.rectangle(frame, (left, top), (right, bottom), (244,42,3),3)
# Draw a label with a name below the face cv2.rectangle(frame, (left -3, top -35), (right+3, top), (244,42,3), cv2.FILLED) font= cv2.FONT_HERSHEY_DUPLEX cv2.putText(frame, name, (left +6, top -6), font,1.0, (255,255,255),1)
returnframe
然后我們創建最后一個函數來計算我們的FPS。在它的最后,它將當前時間存儲在一個變量中,下次我們調用它時,它將比較該時間與新時間以計算出經過的時間,并據此計算FPS。
# Draw a box around the face cv2.rectangle(frame, (left, top), (right, bottom), (244,42,3),3)
# Draw a label with a name below the face cv2.rectangle(frame, (left -3, top -35), (right+3, top), (244,42,3), cv2.FILLED) font= cv2.FONT_HERSHEY_DUPLEX cv2.putText(frame, name, (left +6, top -6), font,1.0, (255,255,255),1)
returnframe
隨著我們的函數布局完成,我們終于準備好進入我們無限重復的while True循環了。這首先使用Picamera2從攝像頭捕獲一幀,然后將該幀輸入到我們的process_frame函數中,該函數輸出所有識別出的人臉及其位置。然后我們將其輸入到display_frame中,該函數獲取人臉位置和識別出的人臉,并將它們繪制在一幀上。這個display_frame變量就是我們稍后將告訴樹莓派顯示的幀:
whileTrue: # Capture a frame from camera frame = picam2.capture_array()
# Process the frame with the function processed_frame = process_frame(frame)
# Get the text and boxes to be drawn based on the processed frame display_frame = draw_results(processed_frame)
之后,我們調用calculate_fps函數來計算我們的FPS,然后我們使用更多OpenCV工具將FPS計數器附加到顯示幀上,然后我們在預覽窗口中顯示它!
# Calculate and update FPS current_fps= calculate_fps()
# Attach FPS counter to the text and boxes cv2.putText(display_frame, f"FPS: {current_fps:.1f}", (display_frame.shape[1] -150,30), cv2.FONT_HERSHEY_SIMPLEX,1, (0,255,0),2)
# Display everything over the video feed. cv2.imshow('Video', display_frame)
最后,在循環結束時,我們檢查是否按下了“q”鍵。如果按下了,我們將退出這個while True循環并運行最后一段代碼,該代碼將安全地停止攝像頭并關閉攝像頭預覽窗口:
# Break the loop and stop the script if 'q' is pressed ifcv2.waitKey(1) == ord("q"): break# By breaking the loop we run this code here which closes everythingcv2.destroyAllWindows()picam2.stop()
原文地址:
https://core-electronics.com.au/guides/raspberry-pi/face-recognition-with-raspberry-pi-and-opencv/
-
操作系統
+關注
關注
37文章
7343瀏覽量
128828 -
人臉識別
+關注
關注
77文章
4119瀏覽量
87882 -
OpenCV
+關注
關注
33文章
651瀏覽量
44486 -
樹莓派
+關注
關注
122文章
2072瀏覽量
109971
發布評論請先 登錄

用樹莓派 + OpenCV 打造人臉識別技術!
評論