表情识别-情感分析-人脸识别(代码+教程)

发布时间:2023年12月21日

表情识别是计算机视觉领域中的一个重要研究方向,它的目标是通过分析人脸表情来判断人的情绪状态。表情识别在很多领域都有广泛的应用,如情感分析、人机交互、智能驾驶等。本文将从以下几个方面来阐述表情识别的相关内容。

一、表情识别的基本原理


表情识别的基本原理是通过对人脸图像进行特征提取,并将这些特征输入到分类器或回归器中进行情绪分类或强度估计。常用的特征提取方法包括传统的手工设计特征和深度学习方法。传统的手工设计特征通常包括颜色特征、纹理特征和形状特征等,但这些方法在处理复杂的表情时往往效果不佳。而深度学习方法通过构建深度神经网络,可以自动地从图像中学习到更具有判别性的特征。

二、表情识别的算法模型


表情识别的算法模型有很多种,其中最常见的是卷积神经网络(CNN)。CNN可以通过卷积层、池化层和全连接层等组件来提取人脸表情中的特征,并将这些特征输入到分类器中进行情绪分类。CNN模型的训练通常需要大量的标注数据,而在实际应用中,我们往往可以通过迁移学习的方式来利用已有的预训练模型,从而减少训练所需的数据量。

三、表情识别的数据集


在表情识别任务中,数据集的选择非常重要。一个好的数据集应该具有较大的规模、多样性的表情类别和高质量的标注。常用的表情识别数据集包括FER2013、CK+和RAF-DB等。这些数据集都包含了大量的人脸图像和对应的表情标签,可以用来进行表情识别算法的训练和评估。

四、表情识别的应用


表情识别在很多领域都有广泛的应用。在情感分析领域,表情识别可以用来分析个体的情感状态,如快乐、悲伤、愤怒等。在人机交互领域,表情识别可以用来改进人机交互的方式,例如根据用户的表情来调整智能设备的行为。在智能驾驶领域,表情识别可以用来监测驾驶员的情绪状态,从而提高驾驶安全性。

五、表情识别的挑战和未来发展方向


表情识别在实际应用中还面临一些挑战。首先,人脸表情的识别受限于光照、姿态和遮挡等因素的影响,因此如何提高模型的鲁棒性和泛化能力是一个重要问题。其次,对于一些复杂的表情,如微笑和愤怒等,表情识别的性能仍然有待提高。未来的发展方向包括进一步改进深度学习模型的性能和效率,提高表情识别的准确性和实时性。

总结起来,表情识别是计算机视觉领域中的重要任务之一,它的基本原理是通过提取人脸表情的特征并将其输入到分类器中进行情绪分类。表情识别的算法模型主要包括卷积神经网络,数据集的选择也是非常重要的。表情识别在情感分析、人机交互和智能驾驶等领域都有广泛的应用,并面临一些挑战和发展方向。随着深度学习技术的不断发展,表情识别的准确性和实时性将会得到进一步提高。

表情识别

面部情绪识别(FER)是指根据面部表情识别和分类人类情绪的过程。通过分析面部特征和模式,机器可以对一个人的情绪状态作出有根据的推断。这个面部识别的子领域高度跨学科,涉及计算机视觉、机器学习和心理学等领域的知识。

应用领域
以下是一些关键领域,其中这项技术可能有所帮助:

社交和内容创作平台:
根据情感反馈个性化用户体验。
自适应学习系统根据学习者的情绪状态调整内容,提供更具针对性的建议。

医疗研究:
监测患者是否存在抑郁、焦虑或其他情绪障碍的迹象。
协助治疗师在治疗过程中跟踪患者的进展或反应。
实时监测应激水平。

驾驶员安全机制:
监测驾驶员是否出现疲劳、注意力分散、压力或昏昏欲睡的迹象。

营销和市场研究:
实时分析观众对广告的反应。
根据观众的情绪状态定制广告内容。
产品测试和反馈。

安全和监控:
在拥挤区域检测可疑或异常行为。
分析公共事件中人群的反应,以确保安全。

构建面部情绪识别系统
本节深入探讨构建面部情绪识别系统的复杂性。我们首先探讨一个专门为面部情绪识别设计的数据集,确保我们的模型有稳健的基础。接下来,我们将介绍一种自定义的VGG13模型架构,该架构以其在分类任务中的效率和准确性而闻名,并阐明其与我们情绪识别目标的相关性。

最后,我们花费一些时间在实验结果部分,提供全面的评估,阐明系统的性能指标及其潜在应用。

面部情绪识别数据集(FER +)


FER + 数据集是原始面部表情识别(FER)数据集的一个重要扩展。为了改进原始数据集的局限性,FER + 提供了更精细和细致的面部表情标签。虽然原始FER数据集将面部表情分类为六种基本情绪——快乐、悲伤、愤怒、惊讶、恐惧和厌恶——但FER + 根据这一基础更进一步引入了两个额外的类别:中性和蔑视。
?

用于人脸检测的RFB-320


Single Shot Multibox Detector (SSD)模型 在识别情绪之前,需要在输入帧中检测人脸。为此,使用了超轻量级人脸检测模型RFB-320。它是一种针对边缘计算设备进行优化的创新人脸检测模型。该模型采用了改进的感受野块(RFB)模块,在不增加计算负担的情况下有效地捕捉多尺度的上下文信息。它在多样化的WIDER FACE数据集上进行训练,并针对320×240的输入分辨率进行优化,具有出色的效率平衡,计算速度为0.2106 GFLOPs,参数量仅为0.3004百万个。该模型基于PyTorch框架开发,取得了令人称赞的平均精度(mAP)为84.78%,在资源受限环境中成为高效人脸检测的强大解决方案。在此实现中,RFB-320 SSD模型以Caffe格式使用。
?

自定义的VGG13模型架构


情绪识别分类模型采用了定制的VGG13架构,专为64×64灰度图像设计。它使用具有最大池化和dropout的卷积层将图像分类为八个情绪类别,以防止过拟合。该架构开始于两个具有64个卷积核的卷积层,然后是最大池化和25%的dropout。额外的卷积层捕捉复杂的特征,两个具有1024个节点的密集层聚合信息,然后是50%的dropout。一个softmax输出层预测情绪类别。
?

让我们编写一些代码来实现这个系统。

首先,需要初始化一些重要的参数。

image_mean = np.array([127, 127, 127])
image_std = 128.0
iou_threshold = 0.3
center_variance = 0.1
size_variance = 0.2
min_boxes = [
    [10.0, 16.0, 24.0], 
    [32.0, 48.0], 
    [64.0, 96.0], 
    [128.0, 192.0, 256.0]
]
strides = [8.0, 16.0, 32.0, 64.0]
threshold = 0.5

?image_mean: 在RGB通道上进行图像归一化的均值。
image_std: 图像归一化的标准差。
iou_threshold: 确定边界框匹配的交并比(IoU)度量的阈值。
center_variance: 预测的边界框中心坐标的缩放因子。
size_variance: 预测的边界框尺寸的缩放因子。
min_boxes: 不同尺寸对象的最小边界框尺寸。
strides: 根据图像大小控制特征图的尺度。
threshold: 目标检测的置信度阈值。

def define_img_size(image_size):
    shrinkage_list = []
    feature_map_w_h_list = []
    for size in image_size:
        feature_map = [int(ceil(size / stride)) for stride in strides]
        feature_map_w_h_list.append(feature_map)
 
    for i in range(0, len(image_size)):
        shrinkage_list.append(strides)
    priors = generate_priors(
        feature_map_w_h_list, shrinkage_list, image_size, min_boxes
    )
    return priors

上述的 define_img_size 函数旨在为目标检测任务生成先验边界框(priors)。该函数以 image_size 参数作为输入,根据提供的图像尺寸和一组预定义的步长值计算特征图的尺寸。这些特征图的尺寸反映了卷积神经网络(CNN)层对不同输入图像尺度的期望输出尺寸。实质上,SSD中的先验边界框提供了一种高效的方法,可以在网络的单次前向传递中同时预测多个边界框及其关联的类别得分,从而实现实时目标检测。

def FER_live_cam():
    emotion_dict = {
        0: 'neutral', 
        1: 'happiness', 
        2: 'surprise', 
        3: 'sadness',
        4: 'anger', 
        5: 'disgust', 
        6: 'fear'
    }
 
    # cap = cv2.VideoCapture('video1.mp4')
    cap = cv2.VideoCapture(0)
 
    frame_width = int(cap.get(3))
    frame_height = int(cap.get(4))
    size = (frame_width, frame_height)
    result = cv2.VideoWriter('result.avi', 
                         cv2.VideoWriter_fourcc(*'MJPG'),
                         10, size)
 
    # Read ONNX model
    model = 'onnx_model.onnx'
    model = cv2.dnn.readNetFromONNX('emotion-ferplus-8.onnx')
     
    # Read the Caffe face detector.
    model_path = 'RFB-320/RFB-320.caffemodel'
    proto_path = 'RFB-320/RFB-320.prototxt'
    net = dnn.readNetFromCaffe(proto_path, model_path)
    input_size = [320, 240]
    width = input_size[0]
    height = input_size[1]
    priors = define_img_size(input_size)
 
    while cap.isOpened():
        ret, frame = cap.read()
        if ret:
            img_ori = frame
            #print("frame size: ", frame.shape)
            rect = cv2.resize(img_ori, (width, height))
            rect = cv2.cvtColor(rect, cv2.COLOR_BGR2RGB)
            net.setInput(dnn.blobFromImage(
                rect, 1 / image_std, (width, height), 127)
            )
            start_time = time.time()
            boxes, scores = net.forward(["boxes", "scores"])
            boxes = np.expand_dims(np.reshape(boxes, (-1, 4)), axis=0)
            scores = np.expand_dims(np.reshape(scores, (-1, 2)), axis=0)
            boxes = convert_locations_to_boxes(
                boxes, priors, center_variance, size_variance
            )
            boxes = center_form_to_corner_form(boxes)
            boxes, labels, probs = predict(
                img_ori.shape[1], 
                img_ori.shape[0], 
                scores, 
                boxes, 
                threshold
            )
            gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
            for (x1, y1, x2, y2) in boxes:
                w = x2 - x1
                h = y2 - y1
                cv2.rectangle(frame, (x1,y1), (x2, y2), (255,0,0), 2)
                resize_frame = cv2.resize(
                    gray[y1:y1 + h, x1:x1 + w], (64, 64)
                )
                resize_frame = resize_frame.reshape(1, 1, 64, 64)
                model.setInput(resize_frame)
                output = model.forward()
                end_time = time.time()
                fps = 1 / (end_time - start_time)
                print(f"FPS: {fps:.1f}")
                pred = emotion_dict[list(output[0]).index(max(output[0]))]
                cv2.rectangle(
                    img_ori, 
                    (x1, y1), 
                    (x2, y2), 
                    (0, 255, 0), 
                    2,
                    lineType=cv2.LINE_AA
                )
                cv2.putText(
                    frame, 
                    pred, 
                    (x1, y1), 
                    cv2.FONT_HERSHEY_SIMPLEX, 
                    0.8, 
                    (0, 255, 0), 
                    2,
                    lineType=cv2.LINE_AA
                )
 
            result.write(frame)
         
            cv2.imshow('frame', frame)
            if cv2.waitKey(1) & 0xFF == ord('q'):
                break
        else:
            break
 
    cap.release()
    result.release()
    cv2.destroyAllWindows()

FER_live_cam() 函数对视频帧进行实时的面部情绪识别。首先,它设置了一个字典 emotion_dict,将数字情绪类别索引映射到可读的情绪标签。视频源被初始化,尽管也可以使用网络摄像头输入。该函数还初始化了一个输出视频写入器,用于保存带有情绪注释的处理过的帧。主要的情绪预测模型以ONNX格式保存,在使用OpenCV DNN的 readNetFromONNX 方法读取并与以Caffe格式保存的RFB-30 SSD人脸检测模型一起加载。在逐帧处理视频时,人脸检测模型通过边界框识别出人脸。

检测到的人脸在输入情绪识别模型之前经过预处理,包括调整大小和转换为灰度图像。通过从模型的输出分数中选择最大值确定识别出的情绪,并使用 emotion_dict 将其映射到标签。然后,在检测到的人脸周围添加矩形框和情绪标签,将帧保存到输出视频文件中,并实时显示。用户可以通过按下 ‘q’ 键停止视频显示。一旦视频处理完成或中断,资源如视频捕获和写入器将被释放,并关闭任何打开的窗口。值得注意的是,该函数引用了一些在其作用域内未定义的变量和辅助函数,这表明它们是整个代码库的一部分。
?

?框和情绪标签,将帧保存到输出视频文件中,并实时显示。用户可以通过按下 ‘q’ 键停止视频显示。一旦视频处理完成或中断,资源如视频捕获和写入器将被释放,并关闭任何打开的窗口。值得注意的是,该函数引用了一些在其作用域内未定义的变量和辅助函数,这表明它们是整个代码库的一部分。

QQ767172261?


?

?

文章来源:https://blog.csdn.net/2301_78240361/article/details/135122661
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。