在本教程中,我們將在 Raspberry Pi 4 上實現(xiàn)情緒識別系統(tǒng)或面部表情識別系統(tǒng)。我們將應(yīng)用預(yù)訓(xùn)練模型從實時視頻流中識別人的面部表情。 “ FER2013 ”??數(shù)據(jù)集用于在類似 VGG 的卷積神經(jīng)網(wǎng)絡(luò) (CNN) 的幫助下訓(xùn)練模型。
面部表情識別系統(tǒng)可用于多種應(yīng)用。它可以用來研究或分析人類的情緒。許多公司正在植入面部表情識別系統(tǒng)來研究員工的抑郁程度。一些游戲公司正在應(yīng)用面部識別系統(tǒng)來記錄游戲玩家在游戲過程中的滿意度。我們將在 Raspberry Pi 上實現(xiàn)一個簡單方便的系統(tǒng)來識別人的表情。
在樹莓派上執(zhí)行面部表情識別的步驟
要在樹莓派上實現(xiàn)表情識別,我們必須遵循下面提到的三個步驟。
Step-1:檢測輸入視頻流中的人臉。
第 2 步:找到人臉的感興趣區(qū)域 (ROI)。
Step-3:應(yīng)用面部表情識別模型來預(yù)測人的表情。
我們在這里使用六個類別,即“憤怒”、“恐懼”、“快樂”、“中性”、“悲傷”、“驚喜”。因此,預(yù)測的圖像將屬于這些類別。我們之前已經(jīng)將 Raspberry Pi 用于其他一些圖像處理項目,例如 面部標(biāo)志檢測 和 人臉識別應(yīng)用程序,如果您有興趣,也可以查看它們。
面部表情識別所需的組件
該項目不涉及太多硬件,您只需要:
樹莓派
Pi 相機模塊
在這里,我們只需要在您的 Raspberry Pi 上安裝一個帶有 OpenCV 的 RPi4 和 Pi 攝像頭模塊。 OpenCV 在這里用于 數(shù)字圖像處理。數(shù)字圖像處理最常見的應(yīng)用是 物體檢測、 人臉識別和 人數(shù)統(tǒng)計。
在樹莓派 4 上安裝 OpenCV
在安裝 OpenCV 和其他依賴項之前,Raspberry Pi 需要完全更新。使用以下命令將 Raspberry Pi 更新到其最新版本:
?
sudo apt-get 更新
?
然后使用以下命令安裝在 Raspberry Pi 上安裝 OpenCV 所需的依賴項。
?
sudo apt-get install libhdf5-dev -y sudo apt-get install libhdf5-serial-dev –y sudo apt-get install libatlas-base-dev –y sudo apt-get install libjasper-dev -y sudo apt-get install libqtgui4 –y sudo apt-get install libqt4-test –y
?
之后,使用下面給出的命令在您的 Raspberry Pi 上安裝 OpenCV。
?
pip3 安裝 opencv-contrib-python==4.1.0.25
?
在樹莓派 4 上安裝 TensorFlow 和 Keras
在安裝 Tensorflow 和 Keras 之前,請安裝以下提到的所需庫。
?
sudo apt-get install python3-numpy sudo apt-get install libblas-dev sudo apt-get install liblapack-dev sudo apt-get install python3-dev sudo apt-get install libatlas-base-dev sudo apt-get install gfortran sudo apt-get install python3-setuptools sudo apt-get install python3-scipy sudo apt-get 更新 sudo apt-get install python3-h5py
?
Tensorflow 和 Keras 庫可以通過在終端中使用 pip(如果您將 python3 作為 raspberry pi 上的默認(rèn) python 環(huán)境,則使用 pip3 命令)命令安裝。
?
pip3 安裝張量流 pip3 安裝 keras
?
為面部表情識別編程 Raspberry Pi
?可以從以下鏈接下載 Raspberry Pi 項目目錄上的完整?面部表情識別。
樹莓派人臉表情識別項目目錄下載?
在這里,我們將解釋代碼的重要部分,以便更好地解釋。下載的項目文件夾包含一個子文件夾 (Haarcascades)、一個 Python 文件 (emotion1.py) 和模型 (ferjj.h5)。
通過導(dǎo)入下面提到的重要包來啟動代碼。
注意:我們使用TensorFlow API來導(dǎo)入Keras庫。
?
從 tensorflow.keras 導(dǎo)入順序 從 tensorflow.keras.models 導(dǎo)入 load_model 導(dǎo)入簡歷2 將 numpy 導(dǎo)入為 np 從 tensorflow.keras.preprocessing.image 導(dǎo)入 img_to_array
?
接下來,是使用從 Keras 庫導(dǎo)入的load_model()函數(shù)加載預(yù)訓(xùn)練模型(在項目文件夾中提供) 。在下一行中,創(chuàng)建一個字典并將標(biāo)簽分配給我們擁有的 6 個類。
?
# 我們有 6 個模型標(biāo)簽 class_labels = {0:“憤怒”,1:“恐懼”,2:“快樂”,3:“中性”,4:“悲傷”,5:“驚喜”} 類=列表(class_labels.values()) # 打?。悩?biāo)簽)
?
現(xiàn)在,Haarcascade 分類器的路徑是通過使用OpenCV 庫中的CascadeClassifier()函數(shù)提供的。
?
face_classifier = cv2.CascadeClassifier('./Haarcascades/haarcascade_frontalface_default.xml')
?
text_on_detected_boxes?()函數(shù)可用于設(shè)計檢測到的人臉的輸出標(biāo)簽。text_on_detected_boxes()的參數(shù)?已經(jīng)有了它們的默認(rèn)值。您可以根據(jù)需要更改這些。
?
# 此函數(shù)用于設(shè)計預(yù)測圖像框上的覆蓋文本。 def text_on_detected_boxes(text,text_x,text_y,image,font_scale = 1, 字體 = cv2.FONT_HERSHEY_SIMPLEX, FONT_COLOR = (0, 0, 0), FONT_THICKNESS = 2, rectangle_bgr = (0, 255, 0)):
?
在圖像上測試我們的面部表情識別:
在face_detector_image(img)函數(shù)中, cvtColor()函數(shù)用于將輸入圖像轉(zhuǎn)換為灰度。如下所示,此處拍攝的示例圖像被轉(zhuǎn)換為??灰度。
然后從圖像中提取人臉的感興趣區(qū)域 ( ROI )。該函數(shù)返回三個重要因素,即人臉的 ROI、人臉的坐標(biāo)和原始圖像。已在檢測到的面部上繪制了一個矩形。將圖像轉(zhuǎn)換為灰度并在我們的 ROI 周圍繪制一個框的代碼如下所示。
def face_detector_image(img):
?
gray = cv2.cvtColor(img.copy(), cv2.COLOR_BGR2GRAY) # 將圖像轉(zhuǎn)換為灰度圖像 faces = face_classifier.detectMultiScale(gray, 1.3, 5) 如果面孔是(): 返回 (0, 0, 0, 0), np.zeros((48, 48), np.uint8), img 所有人臉 = [] 矩形 = [] 對于面中的 (x, y, w, h): cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2) roi_gray = 灰色[y:y + h, x:x + w] roi_gray = cv2.resize(roi_gray, (48, 48), interpolation=cv2.INTER_AREA) allfaces.append(roi_gray) rects.append((x, w, y, h)) 返回 rects, allfaces, img
?
在程序的這一部分中,通過提供 ROI 值來應(yīng)用模型。函數(shù)下的前兩行用于獲取輸入圖像并將其傳遞給face_detector_image(img)函數(shù),如上一節(jié)所述。
預(yù)測后,輸出結(jié)果與檢測到的人臉一起顯示。輸出結(jié)果顯示在我們之前創(chuàng)建的class_labels 字典中。我們正在使用text_on_detected_boxes()函數(shù)來設(shè)計檢測到的面部上的標(biāo)簽。imshow ()函數(shù)用于顯示窗口。
def 情感圖像(imgPath):
?
img = cv2.imread(imgPath) rects, faces, image = face_detector_image(img) 我 = 0 面對面: roi = face.astype("float") / 255.0 roi = img_to_array(roi) roi = np.expand_dims(roi, 軸 = 0) # 對 ROI 進行預(yù)測,然后查找類 preds = 分類器.predict(roi)[0] 標(biāo)簽 = class_labels[preds.argmax()] label_position = (rects[i][0] + int((rects[i][1] / 2)), abs(rects[i][2] - 10)) 我 = + 1 # 在圖片上疊加我們檢測到的情緒 text_on_detected_boxes(標(biāo)簽,label_position[0],label_position[1],圖像) cv2.imshow("情緒檢測器", image) cv2.waitKey(0) cv2.destroyAllWindows()
?
視頻流上的面部表情識別:
face_detector_video?(img)函數(shù)用于檢測視頻流上的人臉。我們將輸入幀作為圖像提供給此函數(shù)。此函數(shù)返回檢測到的人臉的坐標(biāo)、人臉的感興趣區(qū)域 (ROI)和原始幀。rectangle()函數(shù)用于在檢測到的面上繪制一個重疊的矩形。
?
def face_detector_video(img): # 將圖像轉(zhuǎn)換為灰度 灰色 = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) faces = face_classifier.detectMultiScale(gray, 1.3, 5) 如果面孔是(): 返回 (0, 0, 0, 0), np.zeros((48, 48), np.uint8), img 對于面中的 (x, y, w, h): cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 厚度=2) roi_gray = 灰色[y:y + h, x:x + w] roi_gray = cv2.resize(roi_gray, (48, 48), interpolation=cv2.INTER_AREA) 返回 (x, w, y, h), roi_gray, img
?
在本節(jié)中,我們將應(yīng)用我們的模型來識別視頻流上的表達(dá),并在視頻流上實時顯示預(yù)測輸出。
在前兩行中,我們從輸入視頻流中提取一幀。然后,將幀輸入face_detector_video(frame)函數(shù)?,F(xiàn)在,分類器中的predict()函數(shù)用于預(yù)測檢測到的人臉的表情。然后我們?yōu)槟樕系拿總€預(yù)測分配class_labels。現(xiàn)在,imshow()用于在每個面上顯示帶有已識別表情的窗口。
?
def 情感視頻(上限): 而真: ret, frame = cap.read() 矩形、面部、圖像 = face_detector_video(frame) 如果 np.sum([face]) != 0.0: roi = face.astype("float") / 255.0 roi = img_to_array(roi) roi = np.expand_dims(roi, 軸 = 0) # 對 ROI 進行預(yù)測,然后查找類 preds = 分類器.predict(roi)[0] 標(biāo)簽 = class_labels[preds.argmax()] label_position = (rect[0] + rect[1]//50, rect[2] + rect[3]//50) text_on_detected_boxes(label, label_position[0], label_position[1], image) # 您可以將此函數(shù)用于您的另一個 opencv 項目。 fps = cap.get(cv2.CAP_PROP_FPS) cv2.putText(圖像, str(fps),(5, 40), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2) 別的: cv2.putText(image, "No Face Found", (5, 40), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 2) cv2.imshow('全部',圖片) 如果 cv2.waitKey(1) & 0xFF == ord('q'): 休息 帽釋放() cv2.destroyAllWindows()
?
這是代碼的主要功能。在主函數(shù)中可以使用emotionVideo()函數(shù)和emotionImage()函數(shù)。如果您想在圖像上使用面部表情識別,那么只需注釋主函數(shù)的前兩行并取消注釋其余兩行。但請確保您在IMAGE_PA?TH 變量中提供輸入圖像的路徑。
?
如果 __name__ == '__main__': camera = cv2.VideoCapture(0) # 如果您使用的是 USB 攝像頭,則更改使用 1 而不是 0。 情感視頻(相機) # IMAGE_PATH = "提供圖片路徑" #emotionImage(IMAGE_PATH) # 如果你在圖片上使用這個,請?zhí)峁┞窂?/pre>?
在 Raspberry Pi 上測試我們的面部表情識別系統(tǒng)
在啟動 Python 腳本之前,將 Raspberry Pi 相機模塊與 Pi 連接,如下所示:
現(xiàn)在,檢查 Pi 相機是否正常工作。查看相機后,啟動 Python 腳本,您會發(fā)現(xiàn)彈出一個窗口,其中包含您的視頻源。一旦 Pi 檢測到表達(dá)式,它將以綠色框顯示在視頻源上。
from tensorflow.keras import Sequential
from tensorflow.keras.models import load_model
import cv2
import numpy as np
from tensorflow.keras.preprocessing.image import img_to_array
# 加載模型
model = Sequential()
classifier = load_model('ferjj.h5') #這個模型有一組 6 個類
# 我們有模型的 6 個標(biāo)簽
class_labels = {0: 'Angry', 1: 'Fear', 2: 'Happy', 3: 'Neutral', 4: 'Sad', 5 : '驚喜'}
classes = list(class_labels.values())
# print(class_labels)
face_classifier = cv2.CascadeClassifier('./Haarcascades/haarcascade_frontalface_default.xml')
# 此函數(shù)用于設(shè)計預(yù)測圖像框上的覆蓋文本。
def text_on_detected_boxes(text,text_x,text_y,image,font_scale = 1,
font = cv2.FONT_HERSHEY_SIMPLEX,
FONT_COLOR = (0, 0, 0),
FONT_THICKNESS = 2,
rectangle_bgr = (0, 255, 0)):
# 得到寬度和文本框的高度
(text_width, text_height) = cv2.getTextSize(text, font, fontScale=font_scale, thickness=2)[0]
# 設(shè)置框的坐標(biāo)
box_coords = ((text_x-10, text_y+4) , (text_x + text_width+10, text_y - text_height-5))
# 繪制檢測到的框和標(biāo)簽
cv2.rectangle(image, box_coords[0], box_coords[1], rectangle_bgr, cv2.FILLED)
cv2.putText(image, text, (text_x, text_y), font, fontScale=font_scale, color=FONT_COLOR,thickness=FONT_THICKNESS)
# 檢測圖像上的情緒:
def face_detector_image(img):
gray = cv2.cvtColor(img .copy(), cv2.COLOR_BGR2GRAY) # 將圖像轉(zhuǎn)換為灰度圖像
faces = face_classifier.detectMultiScale(gray, 1.3, 5)
if faces is ():
return (0, 0, 0, 0), np.zeros(( 48, 48), np.uint8), img
allfaces = []
rects = []
for (x, y, w, h) in faces:
cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)
roi_gray = gray[y:y + h, x:x + w]
roi_gray = cv2.resize(roi_gray, (48, 48), interpolation=cv2.INTER_AREA)
allfaces.append(roi_gray)
rects.append((x, w, y, h))
返回 rects, allfaces, img
defemotionImage(imgPath):
img = cv2.imread(imgPath)
rects, faces, image = face_detector_image(img)
i = 0
表示人臉:
roi = face.astype("float") / 255.0
roi = img_to_array(roi)
roi = np. expand_dims(roi, axis=0)
# 對 ROI 進行預(yù)測,然后查找類
preds = classifier.predict(roi)[0]
label = class_labels[preds.argmax()]
label_position = (rects[i][0 ] + int((rects[i][1] / 2)), abs(rects[i][2] - 10))
i = + 1
# 在圖片上疊加我們檢測到的情緒
text_on_detected_boxes(label, label_position[0],label_position[1], image)
cv2.imshow("Emotion Detector", image)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 檢測到視頻流表達(dá)式
def face_detector_video(img):
# 將圖像轉(zhuǎn)換為灰度
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = face_classifier.detectMultiScale(gray, 1.3, 5)
if faces is ():
return (0, 0 , 0, 0), np.zeros((48, 48), np.uint8), img
for (x, y, w, h) in faces:
cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 厚度=2)
roi_gray = gray[y:y + h, x:x + w]
roi_gray = cv2.resize(roi_gray, (48, 48), interpolation=cv2.INTER_AREA)
return (x, w, y, h), roi_gray, img
defemotionVideo(cap):
while True:
ret, frame = cap.read()
rect, face, image = face_detector_video(frame)
if np.sum([face]) != 0.0:
roi = face.astype("float" ) / 255.0
roi = img_to_array(roi)
roi = np.expand_dims(roi, axis=0)
# 對 ROI 進行預(yù)測,然后查找類
preds = classifier.predict(roi)[0]
label = class_labels[preds.參數(shù)最大值()]
label_position = (rect[0] + rect[1]//50, rect[2] + rect[3]//50)
text_on_detected_boxes(label, label_position[0], label_position[1], image) # 可以用這個為您的另一個 opencv 項目提供功能。
fps = cap.get(cv2.CAP_PROP_FPS)
cv2.putText(image, str(fps),(5, 40), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
else:
cv2.putText(image , "No Face Found", (5, 40), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 2)
cv2.imshow('All', image)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
if __name__ == '__main__':
camera = cv2.VideoCapture(0) # 如果您使用的是 USB 攝像頭,則更改使用 1 而不是
0。emotionVideo(camera)
# IMAGE_PATH = "provide the image path"
#emotionImage(IMAGE_PATH) # If you are using this on an圖片請?zhí)峁┞窂?/p>
評論
查看更多