python实现情绪识别模块,并将模块封装成可执行文件

news2025/2/11 15:54:39

目录:

  • 1.源码:
  • 2.情绪识别模型运行流程:
  • 3.模型封装需要注意的地方:
  • 4.未解决问题:

1.源码:

https://gitcode.com/xyint/deep_learning.git

2.情绪识别模型运行流程:

需要获取用户摄像头权限,摄像头会捕获用户的面部视频流,程序会在每一定时间内抽取一帧做处理,将图片与训练好的模型进行张量运算,最后输出各个情绪可能的百分比,取最高百分比的情绪为本次图片的情绪

由于人的情绪相对来说变化的不会很频繁所以情绪识别结果逻辑实现上是做了一个统计,即每30次情绪识别作为一个整体取其中占比最高的情绪作为本段时间用户的真实情绪,这样可以降低单次运算结果对整体结果的影响

import cv2
import logging
from EmotionDetection import DeepFace
from collections import defaultdict

# 配置日志
logging.basicConfig(
    level=logging.ERROR,  # 仅记录ERROR及以上级别的日志
    format='%(asctime)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler("emotion_recognition.log"),  # 将日志输出到文件
        logging.StreamHandler()  # 仅在出现ERROR时在控制台输出
    ]
)

# 定义情绪与字母的对应关系
emotion_labels = {
    "angry": "a",
    "disgust": "b",
    "fear": "c",
    "happy": "d",
    "sad": "e",
    "surprise": "f",
    "neutral": "g"
}

def update_active_emotion(emotion):
    # 获取对应字母
    label = emotion_labels.get(emotion, '?')  # 如果情绪不在列表中,用 '?' 表示
    try:
        # 打开文件并写入对应字母
        with open("active_emotion", "w") as f:
            f.write(label)
    except Exception as e:
        logging.error(f"无法更新 active_emotion 文件: {e}")

def main():
    # 初始化摄像头(0为默认摄像头)
    cap = cv2.VideoCapture(0)

    if not cap.isOpened():
        logging.error("无法打开摄像头")
        return

    # 可选:设置摄像头分辨率
    cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1024)
    cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 1024)

    # 初始化分析频率控制
    frame_count = 0
    analyze_every_n_frames = 5  # 每隔5帧进行一次情绪分析

    # 情绪统计
    emotion_buffer = []  # 用于存储30次情绪结果
    current_dominant_emotion = "neutral"  # 当前主导情绪
    region = {'x': 0, 'y': 0, 'w': 100, 'h': 100}  # 初始化区域以避免未定义错误

    while True:
        ret, frame = cap.read()
        if not ret:
            logging.error("无法读取帧")
            break

        try:
            if frame_count % analyze_every_n_frames == 0:
                # DeepFace 分析当前帧
                results = DeepFace.analyze(
                    frame, 
                    actions=['emotion'], 
                    enforce_detection=False,
                    detector_backend='opencv'  # 可根据需要更改
                )

                # 如果检测到多张人脸,可以遍历 results
                if isinstance(results, list):
                    faces = results
                else:
                    faces = [results]

                face_detected = False

                for face in faces:
                    if face['region'] is None:
                        # 未检测到人脸
                        logging.error("未检测到人脸")
                        continue

                    face_detected = True
                    region = face['region']
                    emotions = face['emotion']
                    dominant_emotion = face['dominant_emotion']
                    emotion_score = emotions[dominant_emotion]

                    # 将当前情绪添加到缓冲区
                    emotion_buffer.append(dominant_emotion)

                    # 如果缓冲区达到30次,统计主要情绪并清空缓冲区
                    if len(emotion_buffer) >= 30:
                        # 统计每种情绪的出现次数
                        emotion_counter = defaultdict(int)
                        for emotion in emotion_buffer:
                            emotion_counter[emotion] += 1

                        # 找出出现次数最多的情绪
                        if emotion_counter:
                            new_dominant_emotion = max(emotion_counter, key=emotion_counter.get)
                            if new_dominant_emotion != current_dominant_emotion:
                                current_dominant_emotion = new_dominant_emotion
                                logging.error(f"主要情绪已更新为: {current_dominant_emotion}")
                                # 更新 active_emotion 文件
                                update_active_emotion(current_dominant_emotion)

                        # 清空缓冲区
                        emotion_buffer = []
                        
                    current_emotions = emotions

                if not face_detected:
                    # 没有检测到任何人脸,保持上一次的结果
                    pass

        except Exception as e:
            logging.error(f"处理帧时出错: {e}")
            # 仅在出现错误时显示提示
            cv2.putText(frame, "检测出错", (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)

        # # 绘制当前情绪信息(如果有)
        # if current_emotions:
        #     x, y, w, h = region['x'], region['y'], region['w'], region['h']
        #     cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)
        #     text = f"{dominant_emotion} ({current_emotions[dominant_emotion]:.2f})"
        #     cv2.putText(frame, text, (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 255, 0), 2)

        #     # 可选:显示所有情绪分数
        #     offset = 0
        #     for emotion, score in current_emotions.items():
        #         cv2.putText(frame, f"{emotion}: {score:.2f}", (x, y + h + 20 + offset),
        #                     cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 1)
        #         offset += 20
        # else:
        #     # 显示提示
        #     cv2.putText(frame, "未检测到人脸", (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)

        # # 显示视频帧
        # cv2.imshow('Real-time Emotion Recognition', frame)

        # 按下 'q' 键退出
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break

        frame_count += 1

    # 释放资源
    cap.release()
    cv2.destroyAllWindows()

if __name__ == "__main__":
    main()

在这里插入图片描述

按上述逻辑去处理发现识别效果还可

本次没有用太大的模型,大的模型相应的会对算力要求有所提高,占据的资源也会比较大

3.模型封装需要注意的地方:

为什么要封装?封装是为了将程序转换成设备可直接阅读并执行的二进制文件就像c文件一样通过gcc编译成可执行文件,那么没有c环境的设备也能通过可执行文件直接运行编辑好的程序,那么将这个情绪识别模型转换成可执行文件部署到jetson上的时候就不用下载相关python库了

封装好的模型直接做一个函数来使用了,也就是获取用户情绪函数,让它单独做一个进程去使用,将用户的情绪结果放置到active_emotion文件中,其他进程需要使用到用户情绪的时候直接打开文件读取即可为了读取方便可以用a、b、c、d…对应相应情绪

注意:
直接用pyinstaller 封装main.py会导致找不到锁定人脸的xml文件和未能将模型封装到可执行文件中所以要先编辑一下.spec文件,这个文件是告诉pyinstaller如何打包,告诉他要把这些重要文件也打包了

# -*- mode: python ; coding: utf-8 -*-


a = Analysis(
    ['main.py'],  # 主脚本路径
    pathex=[],    # 附加路径(可选)
    binaries=[],  # 二进制依赖(可选)
    datas=[       # 额外的数据文件
        ('/home/saisi/Desktop/emotional/pth/best_model_CNN_RGB_size96.h5', 'pth'),  # 权重文件路径
        ('/home/saisi/.pyenv/versions/narnat/lib/python3.8/site-packages/cv2/data/haarcascade_frontalface_default.xml', 'cv2/data'),  # Haar 文件路径
        ('/home/saisi/.pyenv/versions/narnat/lib/python3.8/site-packages/cv2/data/haarcascade_eye.xml', 'cv2/data')
    ],
    hiddenimports=[],  # 隐藏的依赖模块(可选)
    hookspath=[],      # 自定义 hook 脚本路径(可选)
    hooksconfig={},    # hook 配置(可选)
    runtime_hooks=[],  # 运行时 hook(可选)
    excludes=[],       # 排除的模块(可选)
    noarchive=False,   # 是否禁用归档(可选)
    optimize=0,        # 优化级别(可选)
)

pyz = PYZ(a.pure)

exe = EXE(
    pyz,
    a.scripts,
    [],
    exclude_binaries=True,
    name='main',          # 生成的可执行文件名
    debug=False,          # 是否启用调试模式
    bootloader_ignore_signals=False,
    strip=False,          # 是否剥离符号表
    upx=True,             # 是否启用 UPX 压缩
    console=True,         # 是否显示控制台窗口
    disable_windowed_traceback=False,
    argv_emulation=False,
    target_arch=None,     # 目标架构(可选)
    codesign_identity=None,
    entitlements_file=None,
)

coll = COLLECT(
    exe,
    a.binaries,
    a.datas,
    strip=False,
    upx=True,
    upx_exclude=[],       # 排除 UPX 压缩的文件(可选)
    name='main',          # 生成的可执行文件名
)
    datas=[       # 额外的数据文件
        ('/home/saisi/Desktop/emotional/pth/best_model_CNN_RGB_size96.h5', 'pth'),  # 权重文件路径
        ('/home/saisi/.pyenv/versions/narnat/lib/python3.8/site-packages/cv2/data/haarcascade_frontalface_default.xml', 'cv2/data'),  # Haar 文件路径
        ('/home/saisi/.pyenv/versions/narnat/lib/python3.8/site-packages/cv2/data/haarcascade_eye.xml', 'cv2/data')
    ],

这里是说明这些模型的位置.h5是训练好的模型,xml是opencv锁定人脸的文件,将这俩东西位置指定好后再用pyinstaller打包项目就能正常使用了

# README

# pth存放训练好的模型
# EmotionDetection内是依赖函数
# main.py是主程序
# Main.py用于检测摄像头是否正常
# active_emotion存储主要情绪,用字母对应方便读取
# emotion_recognition.log存储log信息
# 其他无用的东西全部被删掉了

|"requirements.txt"|
|begin|

deepface
Werkzeug
Pillow
requests
opencv-python
numpy
# already install in deepface
# Flask
# opencv-python
# numpy
# tqdm

|end|

### 上述用于下载依赖库

## 直接使用
git clone https://gitee.com/daetz_0/emotion_detection_client_server.git
cd emotion_detection_client_server
pip install -r requirements.txt
python main.py
# use the "q" exit


### 本识别情绪模型接口是最简洁的模型接口删掉了很多不必要的垃圾
### 这个模块做一个接口使用,类似一个函数
### 预计是将其封装成可执行文件,部署到ubantu测试看能否跑通,不行就直接部署要下载库很麻烦
### main.spec用于将此模块封装成可执行文件运行在Linux系统之上
### 打包命令 pyinstaller main.spec
### 需要模型 best_model_CNN_RGB_size96.h5
### https://gitee.com/daetz_0/emotion_detection_client_server/releases/download/model-weight-data-upload/best_model_CNN_RGB_size96.h5

4.未解决问题:

目前用不了GPU,应该是python库版本问题

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2295764.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AH比价格策略源代码

用python 获取在A股和香港上市的公司和在A股和香港上市的公司股票代码和名称并且选出港股和A股涨幅相差比较大的股票 import akshare as akdef get_ah_stocks():# 获取A股股票列表a_stock_list ak.stock_zh_a_spot_em()print(a_stock_list)a_stock_list a_stock_list[[&quo…

群晖安装Gitea

安装Docker Docker运行Gitea 上传gitea包,下载地址:https://download.csdn.net/download/hmxm6/90360455 打开docker 点击印象,点击新增,从文件添加 点击启动 可根据情况,进行高级设置,没有就下一步 点击应…

LabVIEW商业软件开发

在商业软件开发和仪器自动测试领域,LabVIEW以其图形化编程方式、高效的数据采集能力和强大的硬件集成优势,成为众多工程项目的核心开发工具。然而,商业软件的开发远不止编写代码和实现功能那么简单,尤其是在仪器自动测试领域&…

内容中台赋能人工智能技术提升业务创新能力

内容概要 在当今快速变化的市场环境中,企业需要不断寻求创新以保持竞争力。内容中台作为一种新型的内容管理架构,能够极大地提升企业在内容创建、管理和分发方面的效率。通过与人工智能技术的深度融合,企业能够将海量的数据和信息转化为有价…

生成式聊天机器人 -- 基于Pytorch + Global Attention + 双向 GRU 实现的SeqToSeq模型 -- 下

生成式聊天机器人 -- 基于Pytorch Global Attention 双向 GRU 实现的SeqToSeq模型 -- 下 训练Masked 损失单次训练过程迭代训练过程 测试贪心解码(Greedy decoding)算法实现对话函数 训练和测试模型完整代码 生成式聊天机器人 – 基于Pytorch Global Attention 双向 GRU 实…

Netty初学九 心跳与空闲检测

一、网络问题 1.连接假死: 连接假死的现象是:在某一端看来,底层的Tcp连接已经断开,但是应用程序没有捕获到,会认为这条连接仍然是存在的。从TCP层面来说,只有收到四次握手数据包或者一个RST数据包才可以表示…

数据分析如何做EDA

探索性数据分析(EDA,Exploratory Data Analysis)是数据分析过程中至关重要的一步,其目的是通过统计和可视化技术对数据进行初步分析,从而揭示数据的潜在模式、特征和异常值,并为后续的数据预处理、特征工程…

AD域控粗略了解

一、前提 转眼大四,目前已入职上饶一公司从事运维工程师,这与我之前干的开发有着很大的差异,也学习到了许多新的知识。今天就写下我对于运维工作中常用的功能——域控的理解。 二、为什么要有域控,即域控的作用 首先我们必须要…

【计算机网络】TCP/IP 网络模型有哪几层?

目录 应用层 传输层 网络层 网络接口层 总结 为什么要有 TCP/IP 网络模型? 对于同一台设备上的进程间通信,有很多种方式,比如有管道、消息队列、共享内存、信号等方式,而对于不同设备上的进程间通信,就需要网络通…

【Flink实战】Flink -C实现类路径配置与实现UDF Jar

文章目录 1. 描述2. 使用语法3. -C 适用的 Flink 运行模式4. USING JAR 不可用 1. 描述 Flink 中的 -C 选项用于将 URL 添加到作业的类加载器中。URL可以指向本地、HTTP 服务器或 HDFS 等资源的Jar文件。 注意: 此处的classpath的url必须是一个能够在client&…

【东莞常平】戴尔R710服务器不开机维修分享

1:2025-02-06一位老客户的朋友刚开工公司ERP服务器一台戴尔老服务器故障无法开机,于是经老客户介绍找到我们。 2:服务器型号是DELL PowerEdge R710 这个服务器至少也有15年以上的使用年限了。 3:客户反馈的故障问题为:…

STM32自学记录(八)

STM32自学记录 文章目录 STM32自学记录前言一、ADC杂记二、实验1.学习视频2.复现代码 总结 前言 ADC 一、ADC杂记 ADC其实就是一个电压表,把引脚的电压值测出来,放在一个变量里。 ADC:模拟——数字转换器。 ADC可以将引脚上连续变化的模拟电…

Citespace之关键词爆发检测分析(进阶分析)

在开始citespace进行关键词爆发检测分析之前,如果不会使用citespace的,可以参考我之前这一篇博客: https://blog.csdn.net/m0_56184997/article/details/145536095?spm1001.2014.3001.5501 一、创建工程后进行设置 在创建好工程后&#xf…

解锁 DeepSeek 模型高效部署密码:蓝耘平台深度剖析与实战应用

💖亲爱的朋友们,热烈欢迎来到 青云交的博客!能与诸位在此相逢,我倍感荣幸。在这飞速更迭的时代,我们都渴望一方心灵净土,而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识,也…

NIO——网络编程

文章目录 非阻塞 vs 阻塞阻塞非阻塞多路复用 Selector好处创建绑定 Channel 事件监听 Channel 事件select 何时不阻塞 💡处理 accept 事件事件发生后能否不处理💡 处理 read 事件为何要 iter.remove()💡cancel 的作用💡不处理边界…

IDEA关联Tomcat,部署JavaWeb项目

将IDEA与Tomcat关联 创建JavaWeb项目 创建Demo项目 将Tomcat作为依赖引入到Demo中 添加 Web Application 编写前端和后端代码 配置Tomcat server,并运行

ChatGPT搜索免费开放:AI搜索引擎挑战谷歌霸主地位全面分析

引言 2025年2月6日,OpenAI宣布ChatGPT搜索功能向所有用户免费开放,且无需注册登录。这一重大举措在搜索引擎行业引发巨大反响,有观点认为"谷歌搜索时代即将结束"。本文将深入分析ChatGPT生成式AI搜索对谷歌搜索业务及全球搜索市场…

从0开始掌握Java开发框架:学习路线与系统指南

目录 1. Java 开发框架的分类1. Web 开发框架2. 持久层框架3. 依赖注入框架4. 微服务框架5. 测试框架 2. 主要框架的作用及关系(1)Spring Framework(2)Spring MVC(3)Spring Boot(4)M…

边缘计算网关驱动智慧煤矿智能升级——实时预警、低延时决策与数字孪生护航矿山安全高效运营

迈向智能化煤矿管理新时代 工业物联网和边缘计算技术的迅猛发展,煤矿安全生产与高效运营正迎来全新变革。传统煤矿监控模式由于现场环境复杂、数据采集和传输延时较高,已难以满足当下高标准的安全管理要求。为此,借助边缘计算网关的实时数据…

React Hooks 与 Class 组件相比有何优势

🤍 前端开发工程师、技术日更博主、已过CET6 🍨 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 🕠 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 🍚 蓝桥云课签约作者、上架课程《Vue.js 和 E…