使用 OpenCV 和 FER 在 Python 中进行实时情绪识别

用于实时情感数据的检测、捕获和分析解释的综合 Python 指南

在这里插入图片描述
情绪识别技术是心理学、人工智能和计算机科学的有趣交叉点。我们利用 OpenCV 的视频处理功能和面部情绪识别 (FER) 库来提供视频源的实时情绪检测。

该方法包括捕捉面部表情,使用深度学习模型解释情绪状态,以及动态地可视化这些情绪。实际应用范围包括增强软件用户体验以及为情感感知的人工智能系统提供见解。

本文提供了端到端代码实现。即插即用的解决方案使开发人员和爱好者能够通过网络摄像头或其他视频源(例如屏幕录制或视频文件)实时捕获和分析情绪。

1.技术栈

FER(面部情绪识别)
FER 是一个专注于从面部表情检测情绪的 Python 库。 FER 利用预先训练的深度学习模型,分析图像和视频来识别各种情绪,例如愤怒、厌恶、恐惧、快乐、悲伤、惊讶和中立。它的设计易于使用,可以直接集成到需要情绪检测的项目中。

OpenCV(开源计算机视觉库)
OpenCV 是计算机视觉领域的基础库。它最初由英特尔开发,广泛用于处理图像和视频。 OpenCV支持包括Python在内的多种编程语言,以其在实时应用中的高效率而闻名。

该库在图像和视频处理中发挥着至关重要的作用,使其成为捕获网络摄像头源、视频处理和在图像绘制注释等任务的理想选择

MediaPipe(本文未使用)
在我们讨论实时情感识别技术堆栈的背景下,还值得一提的是 MediaPipe,尽管本文没有使用它。MediaPipe 是 Google 开发的一个框架,用于构建多模式(音频、视频、时间序列等)应用的机器学习管道。它为直播和流媒体提供可定制的机器学习解决方案,其在面部识别、手部跟踪和姿势估计方面的功能十分强大。MediaPipe 是一款功能丰富的工具,有兴趣进一步探索实时图像和视频处理的读者可能会发现它的价值。

它在需要除面部情绪检测之外的更复杂或更多种类型的视觉数据处理和识别任务的场景中尤其有效。

代码示例:

import cv2
import mediapipe as mp

# 初始化 MediaPipe 人脸检测器
mp_face_detection = mp.solutions.face_detection
mp_drawing = mp.solutions.drawing_utils

# 创建人脸检测函数
def detect_faces(image):
    # 将图像从 BGR 转换为 RGB
    image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    
    # 处理图像并进行人脸检测
    with mp_face_detection.FaceDetection(model_selection=1, min_detection_confidence=0.5) as face_detection:
        results = face_detection.process(image)
        
        # 将图像颜色模式转回 BGR,以便于使用 OpenCV 展示
        image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
        
        # 绘制检测到的人脸
        if results.detections:
            for detection in results.detections:
                mp_drawing.draw_detection(image, detection)
                
    return image

# 读取图像
image = cv2.imread('path_to_your_image.jpg')
# 检测人脸
image = detect_faces(image)

# 展示结果
cv2.imshow('Face Detection', image)
cv2.waitKey(0)
cv2.destroyAllWindows()

2.Python实现

实现很简单,主要需要四个库:FER、OpenCV、matplotlib 和 imageio。

为了设置运行情感识别代码的环境,我们需要安装必要的库。通过命令提示符或终端并运行以下命令:

pip install fer
pip install opencv-python
pip install matplotlib
pip install imageio

2.1实时情绪检测

我们介绍使用 Python 进行实时情绪检测的基本概念。我们从演示核心功能的基本代码开始。

此初始示例将重点关注从网络摄像头捕获视频并使用 FER 库实时检测情绪。

虽然我们的示例使用实时网络摄像头源,但你可以轻松调整脚本以与其他来源一起使用。例如,你可以用视频文件甚至实时屏幕录制来替换网络摄像头源。

  1. 启动网络摄像头源:首先,我们使用 OpenCV 从网络摄像头捕获视频。 OpenCV 的VideoCapture函数初始化网络摄像头源。在大多数情况下,VideoCapture的值设置为0会选择默认网络摄像头。
  2. 检测情绪:接下来,我们利用 FER 库,它提供了一个简单的界面来检测视频帧中的情绪。当从网络摄像头捕获帧时,FER 会处理该帧以检测面部及其相应的情绪。
  3. 突出显示检测到的情绪:检测到情绪后,我们使用 OpenCV 函数在视频帧中检测到的面部上绘制边界框和文本注释。文本标签指示检测到的情绪及其置信度。
from fer import FER
import cv2

# Initialize the detector
detector = FER(mtcnn=True)

# Start webcam
cap = cv2.VideoCapture(0)

try:
    while True:
        ret, frame = cap.read()
        if not ret:
            break

        # Detect emotions on the frame
        result = detector.detect_emotions(frame)
        for face in result:
            # Unpack the values
            box = face["box"]
            emotions = face["emotions"]

            x, y, w, h = box
            cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)
            
            # Find the emotion with the highest score
            emotion_type = max(emotions, key=emotions.get)
            emotion_score = emotions[emotion_type]

            # Display the emotion type and its confidence level
            emotion_text = f"{
      
      emotion_type}: {
      
      emotion_score:.2f}"
            cv2.putText(frame, emotion_text, (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 255, 0), 2)

        # Display the resulting frame
        cv2.imshow('Emotion Detection', frame)

        # Break the loop
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
except KeyboardInterrupt:
    print("Interrupted by user")
finally:
    # When everything is done, release the capture
    cap.release()
    cv2.destroyAllWindows()

2.2实时情绪可视化

在基本的实时情绪检测脚本的基础上,我们扩展了功能以包括实时情绪可视化。

此增强功能为我们的情绪检测应用程序添加了更具动态性和交互性的方面,使数据更具吸引力。

创建实时情绪条形图:为了可视化每帧中检测到的情绪,我们使用 matplotlib。我们的设置方法如下:

我们初始化一个 matplotlib 图形,并为每种情绪创建一个带有占位符的条形图。
图表中的每个条形代表一种情绪,其高度将实时更新以反映 FER 检测到的置信水平。

import matplotlib.pyplot as plt

plt.ion()  # Turn on interactive mode
fig, ax = plt.subplots()
emotion_labels = ['angry', 'disgust', 'fear', 'happy', 'sad', 'surprise', 'neutral']
bars = ax.bar(emotion_labels, [0]*7, color='lightblue')

Matplotlib 中的交互模式:通过启用交互模式 ( plt.ion()),matplotlib 的绘图会实时更新。这允许条形图随着情绪检测算法处理的每个新帧动态刷新。

更新图表:我们创建一个函数update_chart来获取检测到的情绪并相应地更新每个条形的高度。处理的每个帧都会调用此函数,以确保图表准确反映检测到的当前情绪。

def update_chart(detected_emotions, bars, ax, fig):
    ax.clear()
    ax.bar(emotion_labels, [detected_emotions.get(emotion, 0) for emotion in emotion_labels], color='lightblue')
    ### [Rest of Chart Formatting]
    fig.canvas.flush_events()

在主循环中集成图表更新:在脚本的主循环中,检测到每一帧的情绪后,我们调用update_chart最新的情绪数据。这使可视化与视频源保持同步。

# Main loop for emotion detection and visualization
while True:
    # [Webcam capture and emotion detection code]

    if largest_face:
        # [Face processing and emotion scoring]
        
        # Update the live bar chart with the latest emotion data
        update_chart(current_emotions, bars, ax, fig)

将所有这些放在一起,我们得到以下的 Python 脚本。

from fer import FER
import cv2
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import imageio
import matplotlib
import time

"""
Real-Time Emotion Detection and Visualization

This script captures video from a webcam, detects emotions on faces in real-time, 
and visualizes the results both in a live bar chart and in the video itself. It also 
saves the video feed with detected emotions, the live bar chart as a GIF, and 
cumulative emotion statistics over time as a static chart. The script uses OpenCV for 
video processing, FER for emotion detection, matplotlib for live chart visualization, 
and imageio for GIF creation.

Key Features:
- Real-time emotion detection from webcam feed.
- Live update of emotion confidence levels in a bar chart.
- Saving the video feed with bounding boxes around faces and emotion labels.
- Generating a GIF of the live emotion bar chart.
- Saving a cumulative chart of emotion statistics over time.
"""


# Set the backend for matplotlib to 'TkAgg' for compatibility with different environments
matplotlib.use('TkAgg')

# Initialize the FER (Face Emotion Recognition) detector using MTCNN
detector = FER(mtcnn=True)

# Start capturing video from the webcam (device 0)
cap = cv2.VideoCapture(0)

# Set a frame rate for recording the video (adjust based on your webcam's capabilities)
frame_rate = 4.3

# Initialize OpenCV's VideoWriter to save the video with the specified frame rate
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('emotion_video.avi', fourcc, frame_rate, (640, 480))

# Set up a matplotlib figure for displaying live emotion detection results
plt.ion()  # Turn on interactive mode for live updates
fig, ax = plt.subplots()
emotion_labels = ['angry', 'disgust', 'fear', 'happy', 'sad', 'surprise', 'neutral']
bars = ax.bar(emotion_labels, [0]*7, color='lightblue') # Initialize bars for each emotion
plt.ylim(0, 1)
plt.ylabel('Confidence')
plt.title('Real-time Emotion Detection')
ax.set_xticklabels(emotion_labels, rotation=45)

# Initialize imageio writer to save live chart updates as a GIF
gif_writer = imageio.get_writer('emotion_chart.gif', mode='I', duration=0.1)

# List to store cumulative emotion statistics for each frame
emotion_statistics = []

# Function to update the live chart
def update_chart(detected_emotions, bars, ax, fig):
    # Clear the current axes and set up the bar chart again
    ax.clear()
    ax.bar(emotion_labels, [detected_emotions.get(emotion, 0) for emotion in emotion_labels], color='lightblue')
    plt.ylim(0, 1)
    plt.ylabel('Confidence')
    plt.title('Real-time Emotion Detection')
    ax.set_xticklabels(emotion_labels, rotation=45)
    fig.canvas.draw()
    fig.canvas.flush_events()

# Start the timer to measure the active time of the webcam
webcam_start_time = time.time()

try:
    while True:
        ret, frame = cap.read() # Read a frame from the webcam
        if not ret:
            break # Break the loop if no frame is captured

        # Detect emotions on the frame
        result = detector.detect_emotions(frame)
        largest_face = None
        max_area = 0

        # Find the largest face in the frame for primary emotion analysis
        for face in result:
            box = face["box"]
            x, y, w, h = box
            area = w * h
            if area > max_area:
                max_area = area
                largest_face = face

        # If a face is detected, display the emotion and update the chart
        if largest_face:
            box = largest_face["box"]
            current_emotions = largest_face["emotions"]

            # Store the emotion data
            emotion_statistics.append(current_emotions)

            x, y, w, h = box
            cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)
            
            emotion_type = max(current_emotions, key=current_emotions.get)
            emotion_score = current_emotions[emotion_type]

            emotion_text = f"{
      
      emotion_type}: {
      
      emotion_score:.2f}"
            cv2.putText(frame, emotion_text, (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 255, 0), 2)

            update_chart(current_emotions, bars, ax, fig)

            out.write(frame) # Write the frame to the video file

            # Save the current state of the bar chart as a frame in the GIF
            fig.canvas.draw()
            image = np.frombuffer(fig.canvas.tostring_rgb(), dtype='uint8')
            image = image.reshape(fig.canvas.get_width_height()[::-1] + (3,))
            gif_writer.append_data(image)

        cv2.imshow('Emotion Detection', frame) # Display the frame

        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
        
except KeyboardInterrupt:
    print("Interrupted by user")

finally:
    webcam_end_time = time.time()  # End timer when webcam window closes
    print(f"Webcam active time: {
      
      webcam_end_time - webcam_start_time:.2f} seconds")

    cap.release()
    cv2.destroyAllWindows()
    plt.close(fig)

    out.release()
    gif_writer.close()

    emotion_df = pd.DataFrame(emotion_statistics)

    plt.figure(figsize=(10, 10))
    for emotion in emotion_labels:
        plt.plot(emotion_df[emotion].cumsum(), label=emotion)
    plt.title('Cumulative Emotion Statistics Over Time')
    plt.xlabel('Frame')
    plt.ylabel('Cumulative Confidence')
    plt.legend()
    plt.savefig('cumulative_emotions.jpg')
    plt.close()

左侧显示实时情绪检测,其中情绪在对象的脸上突出显示。中间的图表动态显示一系列情绪的置信水平,而右侧的图表则跟踪随着时间的推移累积的情绪反应

2.3组合输出

当我们能够以引人入胜的方式可视化数据时,情绪检测技术的真正威力就会显现出来。为了实现这一目标,我们开发了一个脚本,将各种输出组合成一个视觉呈现。该脚本有效地对齐了三个元素:

  1. 实时视频:从网络摄像头源捕获情绪检测,保存为“emotion_video.avi”。
  2. 动态条形图 GIF:检测到的情绪的实时更新表示,存储在“emotion_chart.gif”中。
  3. 静态累积情绪图表:图像文件“cumulative_emotions.jpg”,显示随时间推移聚合的情绪数据。

脚本的关键片段:

  • 读取和处理输入:
static_chart = Image.open('cumulative_emotions.jpg')
video = cv2.VideoCapture('emotion_video.avi')
bar_chart_gif = imageio.mimread('emotion_chart.gif')
  • 组合框架逻辑:
combined_frame = Image.new('RGB', (3 * desired_width, desired_height))
combined_frame.paste(video_frame_resized, (0, 0))
combined_frame.paste(gif_resized, (desired_width, 0))
combined_frame.paste(static_chart_resized, (2 * desired_width, 0))

3.实际应用

  1. 安全系统:情绪识别可以为安全系统添加一个额外的层,可以根据情绪线索识别可疑或异常行为。
  2. 医疗保健和心理健康:在临床环境中,情绪识别可以帮助监测患者的心理健康状态。它在远程治疗过程中特别有用,可以为治疗师提供对患者情绪反应的更多见解。
  3. 用户体验和界面设计:网站和应用程序可以使用情感识别来定制用户体验。例如,检测到困惑或不满意的迹象可以触发有用的提示或引导用户找到更相关的内容。
  4. 机器人和人工智能:在机器人技术中,情绪识别可以使与人工智能和机器人的交互更加自然和直观,特别是在护理或客户服务机器人中。
  5. 辅助技术:对于有言语或听力障碍的个人,情绪识别技术可以通过提供有关说话者情绪状态的附加背景来促进沟通

感谢各位阅读~ 如果有所收获,欢迎关注以支持后序创作。

猜你喜欢

转载自blog.csdn.net/weixin_41914570/article/details/138425156