在本教程中,我们将在 Raspberry Pi 4 上实现情绪识别系统或面部表情识别系统。我们将应用预训练模型从实时视频流中识别人的面部表情。 “ FER2013 ”数据集用于在类似 VGG 的卷积神经网络 (CNN) 的帮助下训练模型。
面部表情识别系统可用于多种应用。它可以用来研究或分析人类的情绪。许多公司正在植入面部表情识别系统来研究员工的抑郁程度。一些游戏公司正在应用面部识别系统来记录游戏玩家在游戏过程中的满意度。我们将在 Raspberry Pi 上实现一个简单方便的系统来识别人的表情。
在树莓派上执行面部表情识别的步骤
要在树莓派上实现表情识别,我们必须遵循下面提到的三个步骤。
Step-1:检测输入视频流中的人脸。
第 2 步:找到人脸的感兴趣区域 (ROI)。
Step-3:应用面部表情识别模型来预测人的表情。
我们在这里使用六个类别,即“愤怒”、“恐惧”、“快乐”、“中性”、“悲伤”、“惊喜”。因此,预测的图像将属于这些类别。我们之前已经将 Raspberry Pi 用于其他一些图像处理项目,例如 面部标志检测 和 人脸识别应用程序,如果您有兴趣,也可以查看它们。
面部表情识别所需的组件
该项目不涉及太多硬件,您只需要:
树莓派
Pi 相机模块
在这里,我们只需要在您的 Raspberry Pi 上安装一个带有 OpenCV 的 RPi4 和 Pi 摄像头模块。 OpenCV 在这里用于 数字图像处理。数字图像处理最常见的应用是 物体检测、 人脸识别和 人数统计。
在树莓派 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 上的默认 python 环境,则使用 pip3 命令)命令安装。
pip3 安装张量流 pip3 安装 keras
为面部表情识别编程 Raspberry Pi
可以从以下链接下载 Raspberry Pi 项目目录上的完整 面部表情识别。
树莓派人脸表情识别项目目录下载
在这里,我们将解释代码的重要部分,以便更好地解释。下载的项目文件夹包含一个子文件夹 (Haarcascades)、一个 Python 文件 (emotion1.py) 和模型 (ferjj.h5)。
通过导入下面提到的重要包来启动代码。
注意:我们使用TensorFlow API来导入Keras库。
从 tensorflow.keras 导入顺序 从 tensorflow.keras.models 导入 load_model 导入简历2 将 numpy 导入为 np 从 tensorflow.keras.preprocessing.image 导入 img_to_array
接下来,是使用从 Keras 库导入的load_model()函数加载预训练模型(在项目文件夹中提供) 。在下一行中,创建一个字典并将标签分配给我们拥有的 6 个类。
# 我们有 6 个模型标签 class_labels = {0:“愤怒”,1:“恐惧”,2:“快乐”,3:“中性”,4:“悲伤”,5:“惊喜”} 类=列表(class_labels.values()) # 打印(类标签)
现在,Haarcascade 分类器的路径是通过使用OpenCV 库中的CascadeClassifier()函数提供的。
face_classifier = cv2.CascadeClassifier('./Haarcascades/haarcascade_frontalface_default.xml')
text_on_detected_boxes ()函数可用于设计检测到的人脸的输出标签。text_on_detected_boxes()的参数 已经有了它们的默认值。您可以根据需要更改这些。
# 此函数用于设计预测图像框上的覆盖文本。 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)函数中, cvtColor()函数用于将输入图像转换为灰度。如下所示,此处拍摄的示例图像被转换为灰度。
然后从图像中提取人脸的感兴趣区域 ( ROI )。该函数返回三个重要因素,即人脸的 ROI、人脸的坐标和原始图像。已在检测到的面部上绘制了一个矩形。将图像转换为灰度并在我们的 ROI 周围绘制一个框的代码如下所示。
def face_detector_image(img):
gray = cv2.cvtColor(img.copy(), 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) allfaces.append(roi_gray) rects.append((x, w, y, h)) 返回 rects, allfaces, img
在程序的这一部分中,通过提供 ROI 值来应用模型。函数下的前两行用于获取输入图像并将其传递给face_detector_image(img)函数,如上一节所述。
预测后,输出结果与检测到的人脸一起显示。输出结果显示在我们之前创建的class_labels 字典中。我们正在使用text_on_detected_boxes()函数来设计检测到的面部上的标签。imshow ()函数用于显示窗口。
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 进行预测,然后查找类 preds = 分类器.predict(roi)[0] 标签 = class_labels[preds.argmax()] label_position = (rects[i][0] + int((rects[i][1] / 2)), abs(rects[i][2] - 10)) 我 = + 1 # 在图片上叠加我们检测到的情绪 text_on_detected_boxes(标签,label_position[0],label_position[1],图像) cv2.imshow("情绪检测器", image) cv2.waitKey(0) cv2.destroyAllWindows()
视频流上的面部表情识别:
face_detector_video (img)函数用于检测视频流上的人脸。我们将输入帧作为图像提供给此函数。此函数返回检测到的人脸的坐标、人脸的感兴趣区域 (ROI)和原始帧。rectangle()函数用于在检测到的面上绘制一个重叠的矩形。
def face_detector_video(img): # 将图像转换为灰度 灰色 = 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
在本节中,我们将应用我们的模型来识别视频流上的表达,并在视频流上实时显示预测输出。
在前两行中,我们从输入视频流中提取一帧。然后,将帧输入face_detector_video(frame)函数。现在,分类器中的predict()函数用于预测检测到的人脸的表情。然后我们为脸上的每个预测分配class_labels。现在,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 进行预测,然后查找类 preds = 分类器.predict(roi)[0] 标签 = 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) # 您可以将此函数用于您的另一个 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()
这是代码的主要功能。在主函数中可以使用emotionVideo()函数和emotionImage()函数。如果您想在图像上使用面部表情识别,那么只需注释主函数的前两行并取消注释其余两行。但请确保您在IMAGE_PA TH 变量中提供输入图像的路径。
如果 __name__ == '__main__': camera = cv2.VideoCapture(0) # 如果您使用的是 USB 摄像头,则更改使用 1 而不是 0。 情感视频(相机) # IMAGE_PATH = "提供图片路径" #emotionImage(IMAGE_PATH) # 如果你在图片上使用这个,请提供路径
在 Raspberry Pi 上测试我们的面部表情识别系统
在启动 Python 脚本之前,将 Raspberry Pi 相机模块与 Pi 连接,如下所示:
现在,检查 Pi 相机是否正常工作。查看相机后,启动 Python 脚本,您会发现弹出一个窗口,其中包含您的视频源。一旦 Pi 检测到表达式,它将以绿色框显示在视频源上。
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 个标签
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')
# 此函数用于设计预测图像框上的覆盖文本。
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]
# 设置框的坐标
box_coords = ((text_x-10, text_y+4) , (text_x + text_width+10, text_y - text_height-5))
# 绘制检测到的框和标签
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) # 将图像转换为灰度图像
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 进行预测,然后查找类
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()
# 检测到视频流表达式
def face_detector_video(img):
# 将图像转换为灰度
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 进行预测,然后查找类
preds = classifier.predict(roi)[0]
label = class_labels[preds.参数最大值()]
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图片请提供路径
评论
查看更多