跳到主要内容

视觉 · 表情与情绪识别

1. 模块概述

  • 主要功能:基于 ResNet50 的面部表情分类,输入一张人脸图片,输出表情类别(如 happy、sad、angry、surprise、neutral 等)与置信度。通常与人脸检测模型配合使用:先检测人脸区域,裁剪后送入表情识别模型。
  • 规格或特性:
    • 支持模型:Emotion ResNet50
    • 输入尺寸:[1, 3, 224, 224]
    • 量化类型:int8
    • 输出:表情类别 + 置信度
    • 推理后端:ONNX Runtime + SpaceMITExecutionProvider
    • 接口形态:C++(vision_service.h)、Python(spacemit_vision wheel:VisionServiceNative
  • 相关目录结构:
examples/emotion/
├── config/emotion.yaml # 配置文件
├── cpp/emotion.cpp # C++ 示例
├── python/emotion.py # Python 示例
└── scripts/ # 模型下载脚本
src/deploy/emotion/ # 部署实现(C++ / Python)
assets/labels/emotion.txt # 表情类别标签

2. 环境准备

前置条件

SDK 源码获取和基础编译环境配置统一参考 2.3-构建编译。完成 SDK 初始化后,回到本文继续执行"构建编译"。

后续命令默认在 spacemit_robot SDK 根目录执行。

构建编译

系统缺少依赖时先安装:

sudo apt install python3-spacemit-ort opencv-spacemit libeigen3-dev spacemit-onnxruntime libyaml-cpp-dev

在 SDK 根目录加载构建环境后编译视觉组件:

source build/envsetup.sh
cd components/model_zoo/vision
mm

SDK 集成构建会把 emotion 等示例程序安装到 output/staging/bin,加载 build/envsetup.sh 后可直接运行。

运行 Python 示例前,需先安装 spacemit_vision wheel:

cd components/model_zoo/vision
python3 -m pip install -U pybind11 build setuptools wheel
cmake -S . -B build && cmake --build build -j
python3 -m pip install --force-reinstall src/python/dist/*.whl
python3 -c "from spacemit_vision import VisionServiceNative; print('ok')"

模型权重默认存放路径为 ~/.cache/models/vision/emotion/。须先手动执行下载脚本;缺失时程序会直接报错(Model file not found)。

3. 示例使用(从 0 跑通)

3.1 表情识别(Python)

前置:见 §2。

步骤 1:下载模型

cd components/model_zoo/vision
bash examples/emotion/scripts/download_models.sh

预期现象:模型文件下载至 ~/.cache/models/vision/emotion/emotion_resnet50_final.q.onnx

步骤 2:下载测试素材

bash scripts/download_assets.sh

步骤 3:运行推理

python3 examples/emotion/python/emotion.py --config examples/emotion/config/emotion.yaml

3.2 表情识别(C++)

前置:见 §2,C++ 编译完成。

步骤 1:下载模型(同 §3.1 步骤 1)

步骤 2:运行推理

emotion examples/emotion/config/emotion.yaml

3.3 运行结果示例

终端输出示例

Emotion: neutral (class 0, score: 0.3035)
Result saved to: result_emotion.jpg

可视化结果

表情识别结果示例

图中展示了输入人脸图像和识别出的表情类别。

4. 应用开发

本章面向应用开发者,说明如何在自己的 C++ 或 Python 应用中集成表情与情绪识别组件。完整接口定义以 include/vision_service.hsrc/python/spacemit_vision/vision_service_native.py 为准;本节介绍常用公开接口和典型调用方式。

4.1 接口说明

表情识别组件的核心入口是 VisionService(C++)和 VisionServiceNative(Python,spacemit_vision wheel)。应用侧通过这些接口加载表情识别模型,并对人脸图像进行情绪分类。

4.1.1 常用数据结构

类型说明
VisionServiceResponse推理响应,results 为 variant 列表 vision::ResultListok/error_message 表示状态。
vision::Classification表情识别结果具体类型,包含表情类别 ID(label)、置信度(score)、各类别概率(class_scores)。

4.1.2 服务初始化

C++ 接口

接口说明参数返回值
VisionService::Create从 YAML 配置文件创建表情识别服务实例config_path:YAML 配置文件路径VisionService 智能指针
VisionService::LastCreateError获取最近一次创建失败的错误信息错误描述字符串

Python 接口

接口说明参数返回值
VisionServiceNative.create从 YAML 配置文件创建服务实例config_path:YAML 路径;model_path_override:可选覆盖模型路径VisionServiceNative 实例
VisionServiceNative.last_create_error获取最近一次创建失败的错误信息错误描述字符串

4.1.3 表情识别

C++ 接口

接口说明参数返回值
Infer对人脸图像进行表情识别image_path:图像文件路径;response:输出 VisionServiceResponseVisionServiceStatus
Infer对 cv::Mat 图像进行表情识别image:OpenCV Mat 对象;response:输出 VisionServiceResponseVisionServiceStatus
LastError获取最近一次推理的错误信息错误描述字符串

Python 接口

接口说明参数返回值
infer_image对图像进行表情分类image_or_path:BGR numpy 数组或图像路径(VisionServiceStatus, results 列表;读取 results[0].class_scores 得各类概率)
get_class_names获取配置中的表情类别名称列表字符串列表
last_error获取最近一次推理错误错误描述字符串

Emotion 为分类模型,get_capabilities() 不注册绘制能力,supports_draw() 恒为 False;可视化请用 cv2.putText 等自行绘制(与 examples/emotion/python/emotion.py 一致)。

4.1.4 性能监控

C++ 接口

接口说明参数返回值
SetTimingOptions启用/禁用性能计时options:VisionServiceTimingOptions 结构体void
GetLastTiming获取最近一次推理的各阶段耗时VisionServiceTiming 结构体(preprocess_ms、model_infer_ms、postprocess_ms、infer_ms 等)

4.2 典型调用流程

4.2.1 C++ 单图表情识别

#include "vision_service.h"
#include <opencv2/opencv.hpp>
#include <iostream>

int main() {
// 1. 创建服务
auto service = VisionService::Create("examples/emotion/config/emotion.yaml");
if (!service) {
std::cerr << "Failed to create service: "
<< VisionService::LastCreateError() << std::endl;
return -1;
}

// 2. 启用性能计时(可选)
VisionServiceTimingOptions timing_opts;
timing_opts.enabled = true;
service->SetTimingOptions(timing_opts);

// 3. 执行推理
VisionServiceResponse response;
VisionServiceStatus ret = service->Infer("face.jpg", &response);
if (ret != VISION_SERVICE_OK) {
std::cerr << "Inference failed: " << service->LastError() << std::endl;
return -1;
}

// 4. 处理结果
if (!response.results.empty()) {
int emotion_class = vision::get_label(response.results[0]);
float emotion_score = vision::get_score(response.results[0]);
std::cout << "Emotion: class " << emotion_class
<< ", Score: " << emotion_score << std::endl;
}

// 5. 查看性能指标(可选)
auto timing = service->GetLastTiming();
std::cout << "Preprocess: " << timing.preprocess_ms << " ms" << std::endl;
std::cout << "Inference: " << timing.model_infer_ms << " ms" << std::endl;
std::cout << "Postprocess: " << timing.postprocess_ms << " ms" << std::endl;

return 0;
}

4.2.2 Python 单图表情识别

import cv2
import numpy as np
from spacemit_vision import VisionServiceNative, VisionServiceStatus

svc = VisionServiceNative.create("examples/emotion/config/emotion.yaml")
face_image = cv2.imread("face.jpg")

status, results = svc.infer_image(face_image)
if status != VisionServiceStatus.OK:
raise RuntimeError(svc.last_error())

if results:
scores = list(results[0].class_scores)
emotion_class = int(np.argmax(scores))
emotion_score = float(scores[emotion_class])
labels = svc.get_class_names()
emotion_name = labels[emotion_class] if emotion_class < len(labels) else f"class_{emotion_class}"
print(f"Emotion: {emotion_name} (class {emotion_class}, score: {emotion_score:.4f})")

# 分类模型无 C++ draw;手动绘制标签
result_image = face_image.copy()
cv2.putText(result_image, f"{emotion_name} {emotion_score:.2f}",
(10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (0, 255, 0), 2)
cv2.imwrite("result.jpg", result_image)

4.3 配置说明

YAML 配置文件是模型加载和推理参数的核心,以下是完整配置项说明:

# 模型文件路径(ResNet50 表情识别模型)
model_path: ~/.cache/models/vision/emotion/emotion_resnet50_final.q.onnx

# 测试图像路径(用于示例程序)
test_image: ~/.cache/assets/image/003_face0.png

# 类别标签文件路径(表情类别)
label_file_path: assets/labels/emotion.txt

# 模型输入尺寸 [height, width]
image_size: [224, 224]

# 部署类名(C++ 模型工厂注册名,Python 通过 yaml 路径间接使用)
class: deploy.emotion.EmotionRecognizer

# 推理参数
default_params:
# 推理线程数(示例默认 8;K3 平台 intra-op 最大建议 8,可按场景调低)
num_threads: 8

# 推理后端(优先使用 SpaceMITExecutionProvider)
providers:
- SpaceMITExecutionProvider
- CPUExecutionProvider # 备用后端

支持的表情类别(参考 assets/labels/emotion.txt):

  • 0: neutral(中性)
  • 1: happiness(快乐)
  • 2: sadness(悲伤)
  • 3: surprise(惊讶)
  • 4: fear(恐惧)
  • 5: disgust(厌恶)
  • 6: anger(愤怒)

参数调优建议

  • image_size:表情识别标准输入为 [224, 224],不建议修改。
  • num_threads:示例 yaml 默认为 8,K3 平台 intra-op 线程数最大建议 8。若 CPU 竞争或延迟不稳定,可尝试降至 4 观察效果,不建议超过 8。
  • providers:优先使用 SpaceMITExecutionProvider 以获得最佳性能。
  • 输入要求:输入应为裁剪对齐后的人脸图像,建议先用人脸检测模型定位人脸区域。

4.4 性能监控

通过启用性能计时,可以分析推理各阶段的耗时,用于性能优化和瓶颈定位。

C++ 示例

VisionServiceTimingOptions opts;
opts.enabled = true;
service->SetTimingOptions(opts);

VisionServiceResponse response;
service->Infer("face.jpg", &response);

auto timing = service->GetLastTiming();
std::cout << "Preprocess: " << timing.preprocess_ms << " ms" << std::endl;
std::cout << "Inference: " << timing.model_infer_ms << " ms" << std::endl;
std::cout << "Postprocess: " << timing.postprocess_ms << " ms" << std::endl;
std::cout << "Total: " << timing.infer_ms << " ms" << std::endl;

性能优化建议

  • 预处理耗时高:表情识别的预处理相对简单(缩放 + 归一化),耗时应较低。
  • 推理耗时高:确认使用 SpaceMITExecutionProvider,检查线程数设置。
  • 后处理耗时高:表情分类的后处理仅为 softmax,耗时应极低。

参考 demo 路径examples/emotion/

应用案例applications/emotion_detection/(人脸检测 + 表情识别联合应用)

5. 调试指南

  • 启用计时:通过 SetTimingOptions 查看各阶段耗时
  • 输入要求:建议输入裁剪后的人脸图片(224×224),全身照或背景复杂的图片会影响准确率
  • 确认标签文件 assets/labels/emotion.txt 存在

6. 常见问题

现象可能原因处理
Model file not found模型未下载执行 bash examples/emotion/scripts/download_models.sh
No module named 'spacemit_vision'wheel 未安装按 §2 编译并 pip install src/python/dist/*.whl
分类结果不准确输入非人脸图片或人脸过小先用人脸检测裁剪人脸区域,再送入表情识别
标签不匹配标签文件缺失确认 assets/labels/emotion.txt 存在

附录:性能与测试数据

表情识别模型基于 ResNet50 架构,输入尺寸 [1,3,224,224],性能与 ResNet50 图像分类模型相近。具体数据请参考 4.2.6-图像分类 中 ResNet50 的性能数据。

测试方法:使用 onnxruntime_perf_test 工具,4 线程,SpaceMITExecutionProvider,20 次迭代取平均。

onnxruntime_perf_test ~/.cache/models/vision/emotion/emotion_resnet50_final.q.onnx -e spacemit -r 20 -x 1 -S 1 -s -I -c 1 -i "SPACEMIT_EP_INTRA_THREAD_NUM|4"