type
status
date
slug
summary
tags
category
icon
password
comment
一个使用网络摄像头进行实时面部情绪检测的 Python 脚本。它不仅能在视频画面上实时标注情绪,还能动态生成一个条形图,并将所有内容保存下来。
目标
- 从网络摄像头捕获视频。
- 检测视频中的人脸并识别其情绪(如:高兴、悲伤、愤怒等)。
- 在视频画面上用方框和文字标出检测结果。
- 创建一个实时更新的条形图,展示各种情绪的置信度。
- 将处理后的视频、动态图表(GIF)和最终的统计数据保存下来。
核心工具
- fer: 一个非常好用的 Python 库,它封装了深度学习模型,可以轻松实现面部情绪识别。我选择了 mtcnn=True 选项,因为它在人脸检测方面通常更准确。
- OpenCV (cv2): 视频处理的瑞士军刀。用于从摄像头捕获图像、在图像上绘制图形和文字,以及将视频帧写入文件。
- Matplotlib: 用于数据可视化。这里的挑战是创建一个能够 高效 实时更新的图表。
- imageio: 一个简单的库,用来将 matplotlib 图表的每一帧拼接成一个 GIF 动图。
- pandas: 用于在程序结束后对收集到的数据进行整理和分析。
代码
1. 初始化:准备好一切
万事开头难,但这里的初始化过程很直接。首先,加载 FER 检测器和 OpenCV 的摄像头捕获对象。
一个重要的细节是视频保存的分辨率。与其硬编码一个尺寸,不如直接从摄像头读取第一帧,动态获取其宽度和高度。这样可以确保保存的视频 emotion_video.avi 和原始输入尺寸完全一致,避免拉伸变形。
2. 高效的实时图表
这是项目的一个关键点。天真的做法是在每一帧都用 plt.cla() 清除整个图表再重新绘制,但这非常慢,会导致程序卡顿。
更优化的方法是:只创建一次图表,后续只更新数据。
我们先用 plt.bar() 创建一组初始高度为 0 的条形图,并保存这些条形图对象。在主循环中,我们只需要调用 bar.set_height() 来更新每个条形的高度即可。这种方式的性能开销极小。
3. 主循环:检测与可视化
这是程序的核心逻辑,在一个 while True 循环中不断执行:
- 读取帧: 从摄像头获取新的一帧图像。
- 情绪检测: 将图像帧传递给 detector.detect_emotions()。它会返回一个列表,其中包含每个检测到的人脸及其情绪分数。
- 处理结果: 如果检测到了人脸,我们找到最大的那张脸,并提取它的边界框(box)和情绪字典(emotions)。
- 绘制视频: 使用 cv2.rectangle() 和 cv2.putText() 在原始视频帧上绘制方框和最主要的情绪。
- 更新图表: 调用我们之前定义的 update_chart_efficient() 函数,用当前帧的情绪数据更新条形图。
- 保存输出:
- 将绘制好的视频帧写入 out 视频文件。
- 一个巧妙的技巧:将 Matplotlib 图表的画布内容转换为 NumPy 数组,然后写入 GIF 文件。这样就实现了图表的实时录制。
这是将 Matplotlib 图表保存为图像帧的关键代码:
4. 收尾:数据分析与资源释放
当用户按下 'q' 键后,循环结束。此时,必须做好清理工作:释放摄像头、关闭视频和 GIF 文件写入器、销毁所有 OpenCV 窗口。
最后,我们将循环中收集到的每一帧的情绪数据(一个字典列表)转换成一个 Pandas DataFrame。这使得后续分析变得非常容易。例如,我们可以使用 .cumsum() 计算每种情绪的累积得分,并绘制一个折线图,直观地展示在整个检测过程中,哪些情绪占据了主导地位。
总结
这个项目是一个很好的实践,它融合了计算机视觉、数据可视化和实时处理。最大的收获是理解了如何通过“只更新数据,不重绘对象”的方式来优化 Matplotlib 的实时性能,以及如何将动态图表保存为 GIF。fer 库的易用性也大大降低了进入情绪识别领域的门槛。
完整代码:
python-fer-real-time-emotion-detection
zhx1012 • Updated Sep 15, 2025
- Author:Max
- URL:https://www.zhx1012.top//article/python-fer-real-time-emotion-detection
- Copyright:All articles in this blog, except for special statements, adopt BY-NC-SA agreement. Please indicate the source!