Skip to content
清晨的一缕阳光
返回

面部表情技术

面部表情技术

面部表情是人类情感交流的主要方式,55% 的情感信息通过面部传递。人形机器人要实现自然的人机交互,必须具备面部表情能力。本文深入解析人形机器人面部表情技术的驱动方式、表情生成、情感识别与应用。

一、面部表情基础

1.1 人类面部解剖

面部肌肉系统

人类面部肌肉(44 块)

├── 额部
│   ├── 额肌:抬眉、皱眉
│   └── 降眉肌:降眉

├── 眼部
│   ├── 眼轮匝肌:闭眼、眨眼
│   ├── 皱眉肌:皱眉
│   └── 提上睑肌:睁眼

├── 鼻部
│   ├── 鼻肌:皱鼻
│   └── 降鼻中隔肌:降鼻尖

├── 口部
│   ├── 口轮匝肌:闭嘴、噘嘴
│   ├── 提上唇肌:提上唇
│   ├── 降下唇肌:降下唇
│   ├── 颧大肌:微笑(拉嘴角)
│   ├── 颧小肌:辅助微笑
│   ├── 颊肌:鼓腮
│   └── 降口角肌:降嘴角(悲伤)

└── 颈部
    └── 颈阔肌:拉下唇和嘴角

面部神经:
├── 面神经(CN VII):主要运动神经
└── 三叉神经(CN V):感觉 + 咀嚼

1.2 面部动作编码系统(FACS)

FACS 定义

主要动作单元

FACS 动作单元(部分)

├── 眉部动作
│   ├── AU1:内眉上扬(悲伤)
│   ├── AU2:外眉上扬(惊讶)
│   ├── AU4:皱眉(愤怒、专注)
│   └── AU1+2+4:复杂表情

├── 眼部动作
│   ├── AU5:上睑提升(惊讶)
│   ├── AU6:脸颊提升(真笑)
│   ├── AU7:眼睑收紧(愤怒)
│   └── AU43:闭眼

├── 鼻部动作
│   ├── AU9:皱鼻(厌恶)
│   └── AU10:上唇提升(厌恶)

├── 口部动作
│   ├── AU12:嘴角拉向耳(微笑)
│   ├── AU14:酒窝(抿嘴)
│   ├── AU15:嘴角下拉(悲伤)
│   ├── AU16:下唇下拉
│   ├── AU17:下巴提升(威胁)
│   ├── AU18:噘嘴
│   ├── AU20:水平拉嘴(恐惧)
│   ├── AU23:缩唇
│   └── AU24:压唇

└── 头部动作
    ├── AU51:头部左转
    ├── AU52:头部右转
    ├── AU53:头部上抬
    └── AU54:头部下低

基本表情与 AU 组合:
├── 快乐:AU6 + AU12(杜兴微笑)
├── 悲伤:AU1 + AU4 + AU15
├── 愤怒:AU4 + AU5 + AU7 + AU23
├── 惊讶:AU1 + AU2 + AU5 + AU26
├── 恐惧:AU1 + AU2 + AU4 + AU20
├── 厌恶:AU9 + AU10
└── 轻蔑:AU14(单侧)

1.3 基本表情理论

Ekman 六种基本表情

跨文化基本表情

├── 快乐(Happiness)
│   ├── 特征:嘴角上扬、眼角皱纹
│   ├── AU:6 + 12
│   └── 识别率:95%+

├── 悲伤(Sadness)
│   ├── 特征:嘴角下拉、内眉上扬
│   ├── AU:1 + 4 + 15
│   └── 识别率:85%+

├── 愤怒(Anger)
│   ├── 特征:皱眉、瞪眼、压唇
│   ├── AU:4 + 5 + 7 + 23
│   └── 识别率:90%+

├── 惊讶(Surprise)
│   ├── 特征:眉眼睁、口张开
│   ├── AU:1 + 2 + 5 + 26
│   └── 识别率:95%+

├── 恐惧(Fear)
│   ├── 特征:眉眼睁、水平拉嘴
│   ├── AU:1 + 2 + 4 + 20
│   └── 识别率:80%+

└── 厌恶(Disgust)
    ├── 特征:皱鼻、上唇提升
    ├── AU:9 + 10
    └── 识别率:90%+

争议表情:
├── 轻蔑(Contempt):单侧 AU14
├── 尴尬(Embarrassment):眼神回避
└── 骄傲(Pride):头部后仰、微笑

二、面部驱动技术

2.1 驱动方式对比

面部驱动技术对比

├── 电机驱动
│   ├── 原理:伺服电机 + 连杆
│   ├── 优点:精确、可靠
│   ├── 缺点:噪音、重量
│   └── 应用:Sophia、Ameca

├── 气动驱动
│   ├── 原理:气动肌肉 + 气管
│   ├── 优点:柔顺、安静
│   ├── 缺点:需要气源、响应慢
│   └── 应用:研究原型

├── SMA 驱动
│   ├── 原理:形状记忆合金丝
│   ├── 优点:紧凑、静音
│   ├── 缺点:响应慢、效率低
│   └── 应用:微型机器人

├── 液压驱动
│   ├── 原理:液体压力
│   ├── 优点:高功率密度
│   ├── 缺点:泄漏风险
│   └── 应用:高端仿生

└── 显示方案
    ├── 原理:LED 屏幕/投影
    ├── 优点:灵活、可编程
    ├── 缺点:非真实、分辨率限
    └── 应用:Pepper、NAO

2.2 电机驱动方案

结构设计

电机驱动面部结构

┌─────────────────────────────────────┐
│  面部皮肤(硅胶)                    │
│  ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲  │
│  │││││││││││││││││││││││  │
│  │  面部机构层                       │
│  │  ├── 连杆机构                     │
│  │  ├── 滑轮系统                     │
│  │  └── 线缆传动                     │
│  │││││││││││││││││││││││  │
│  ╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲  │
├─────────────────────────────────────┤
│  驱动层                              │
│  ├── 伺服电机 × 20-40               │
│  ├── 减速器                         │
│  └── 编码器                         │
├─────────────────────────────────────┤
│  头骨结构                            │
│  ├── 3D 打印/ CNC                    │
│  └── 电机安装座                     │
└─────────────────────────────────────┘

电机配置(典型 32 DOF 面部):
├── 眉部:4 电机(左右各 2)
├── 眼部:4 电机(眼皮、眼球)
├── 鼻部:2 电机
├── 口部:12 电机(嘴唇、嘴角、下巴)
├── 脸颊:4 电机
├── 颈部:4 电机
└── 其他:2 电机(耳朵等)

控制架构

class FacialExpressionController:
    """
    面部表情控制器
    """
    def __init__(self, num_motors=32):
        self.num_motors = num_motors
        
        # 电机参数
        self.motor_positions = np.zeros(num_motors)
        self.motor_limits = self.load_motor_limits()
        
        # 表情库
        self.expression_library = self.load_expressions()
        
        # 混合权重
        self.blend_weights = np.zeros(len(self.expression_library))
    
    def set_expression(self, expression_name, intensity=1.0):
        """
        设置表情
        """
        if expression_name not in self.expression_library:
            return False
        
        # 获取目标电机位置
        target_positions = self.expression_library[expression_name].copy()
        
        # 应用强度
        current = self.motor_positions
        target = current + (target_positions - current) * intensity
        
        # 限制检查
        target = np.clip(target, self.motor_limits[:, 0], self.motor_limits[:, 1])
        
        # 发送命令
        self.send_motor_commands(target)
        
        return True
    
    def blend_expressions(self, expressions):
        """
        混合多个表情
        expressions: [(name1, weight1), (name2, weight2), ...]
        """
        blended = np.zeros(self.num_motors)
        
        for name, weight in expressions:
            if name in self.expression_library:
                blended += self.expression_library[name] * weight
        
        # 归一化
        total_weight = sum(w for _, w in expressions)
        if total_weight > 0:
            blended /= total_weight
        
        self.send_motor_commands(blended)
    
    def transition(self, from_expr, to_expr, duration=1.0):
        """
        表情平滑过渡
        """
        start = self.expression_library.get(from_expr, np.zeros(self.num_motors))
        end = self.expression_library.get(to_expr, np.zeros(self.num_motors))
        
        # 插值
        num_steps = int(duration / 0.016)  # 60fps
        for i in range(num_steps + 1):
            t = i / num_steps
            interpolated = start + (end - start) * t
            self.send_motor_commands(interpolated)
            time.sleep(0.016)
    
    def load_expressions(self):
        """
        加载预定义表情
        基于 FACS 动作单元
        """
        expressions = {
            'neutral': np.zeros(self.num_motors),
            
            'happy': self.create_expression(
                mouth_corner_up=0.8,  # AU12
                cheek_raise=0.6,      # AU6
                eye_narrow=0.3
            ),
            
            'sad': self.create_expression(
                inner_brow_up=0.7,    # AU1
                brow_lower=0.5,       # AU4
                mouth_corner_down=0.8 # AU15
            ),
            
            'angry': self.create_expression(
                brow_lower=0.9,       # AU4
                upper_lid_raise=0.6,  # AU5
                lid_tighten=0.7,      # AU7
                lip_press=0.5         # AU23
            ),
            
            'surprised': self.create_expression(
                brow_raise=0.9,       # AU1+2
                upper_lid_raise=0.9,  # AU5
                jaw_drop=0.8          # AU26
            ),
            
            'disgusted': self.create_expression(
                nose_wrinkle=0.8,     # AU9
                upper_lip_raise=0.7   # AU10
            ),
            
            'afraid': self.create_expression(
                brow_raise=0.8,       # AU1+2
                brow_lower=0.5,       # AU4
                upper_lid_raise=0.7,  # AU5
                mouth_stretch=0.8     # AU20
            ),
        }
        
        return expressions
    
    def create_expression(self, **aus):
        """
        从 AU 创建表情
        """
        motor_positions = np.zeros(self.num_motors)
        
        # AU 到电机的映射(简化)
        au_to_motor = {
            'inner_brow_up': [0, 1],
            'brow_raise': [0, 1, 2, 3],
            'brow_lower': [2, 3],
            'upper_lid_raise': [4, 5],
            'lid_tighten': [4, 5, 6, 7],
            'cheek_raise': [6, 7, 8, 9],
            'nose_wrinkle': [10, 11],
            'upper_lip_raise': [12, 13, 14],
            'mouth_corner_up': [15, 16, 17, 18],
            'mouth_corner_down': [15, 16, 17, 18],
            'lip_press': [19, 20],
            'jaw_drop': [21, 22, 23],
            'mouth_stretch': [15, 16, 17, 18, 24, 25],
        }
        
        for au_name, intensity in aus.items():
            if au_name in au_to_motor:
                for motor_idx in au_to_motor[au_name]:
                    motor_positions[motor_idx] += intensity
        
        # 限制在 0-1 范围
        motor_positions = np.clip(motor_positions, 0, 1)
        
        return motor_positions

2.3 气动驱动方案

气动肌肉面部

气动面部驱动系统

┌─────────────────────────────────────┐
│  面部皮肤(硅胶)                    │
│  - 内嵌气动通道                      │
├─────────────────────────────────────┤
│  气动肌肉层                          │
│  ├── McKibben 肌肉 × 20            │
│  ├── 气管网络                        │
│  └── 快速接头                        │
├─────────────────────────────────────┤
│  气源系统                            │
│  ├── 空压机                          │
│  ├── 储气罐                          │
│  └── 比例阀 × 20                    │
└─────────────────────────────────────┘

性能:
├── 响应时间:50-100 ms
├── 最大应变:20-30%
├── 噪音:<40 dB
└── 重量:500g(不含气源)

优势:
├── 柔顺(安全)
├── 安静(无电机声)
├── 仿人(类似肌肉)
└── 可拉伸

劣势:
├── 需要气源
├── 响应较慢
├── 控制复杂
└── 效率低

2.4 显示方案

LED 屏幕面部

LED 屏幕面部方案

┌─────────────────────────────────────┐
│  透明保护层                          │
├─────────────────────────────────────┤
│  LED 矩阵                            │
│  ├── 分辨率:64×64 或 128×128      │
│  ├── 像素间距:2-4mm                │
│  └── 亮度:500-1000 cd/m²          │
├─────────────────────────────────────┤
│  扩散层                              │
│  - 柔化像素边界                      │
├─────────────────────────────────────┤
│  头骨结构                            │
└─────────────────────────────────────┘

优势:
├── 灵活(任意表情)
├── 可编程(动画、视频)
├── 可靠(无运动部件)
└── 成本可控

劣势:
├── 非真实(像素化)
├── 分辨率限制
├── 无 3D 深度
└── 功耗较高

应用:
├── SoftBank Pepper
├── NAO 机器人
└── 教育、展示机器人

三、表情生成

3.1 表情合成

基于规则的表情合成

class ExpressionSynthesizer:
    """
    表情合成器
    """
    def __init__(self):
        # 基本表情
        self.basic_expressions = {
            'neutral': [0.0] * 32,
            'happy': [0.8, 0.6, 0.0, ...],
            'sad': [0.7, 0.5, 0.8, ...],
            'angry': [0.9, 0.6, 0.7, ...],
            'surprised': [0.9, 0.9, 0.8, ...],
            'disgusted': [0.8, 0.7, 0.0, ...],
            'afraid': [0.8, 0.5, 0.7, ...],
        }
        
        # 强度映射
        self.intensity_map = {
            'slight': 0.3,
            'mild': 0.5,
            'moderate': 0.7,
            'strong': 0.9,
            'extreme': 1.0,
        }
    
    def synthesize(self, emotion, intensity='moderate'):
        """
        合成表情
        """
        base = self.basic_expressions.get(emotion, self.basic_expressions['neutral'])
        scale = self.intensity_map.get(intensity, 0.7)
        
        # 应用强度
        result = [v * scale for v in base]
        
        return result
    
    def blend(self, expr1, expr2, weight=0.5):
        """
        混合两个表情
        weight: 0.0(全 expr1)到 1.0(全 expr2)
        """
        blended = []
        for v1, v2 in zip(expr1, expr2):
            blended.append(v1 * (1 - weight) + v2 * weight)
        
        return blended
    
    def add_micro_expression(self, base_expr, micro_expr, duration=0.2):
        """
        添加微表情
        微表情:短暂、无意识的面部表情
        """
        # 微表情强度较低
        micro_intensity = 0.3
        
        # 时间序列
        frames = []
        num_frames = int(duration / 0.016)  # 60fps
        
        for i in range(num_frames):
            # 淡入
            if i < num_frames / 4:
                t = i / (num_frames / 4)
            # 保持
            elif i < 3 * num_frames / 4:
                t = 1.0
            # 淡出
            else:
                t = 1.0 - (i - 3 * num_frames / 4) / (num_frames / 4)
            
            frame = self.blend(base_expr, micro_expr, t * micro_intensity)
            frames.append(frame)
        
        return frames

3.2 语音同步

唇形同步

class LipSyncController:
    """
    唇形同步控制器
    """
    def __init__(self):
        # 音素到口型的映射
        self.viseme_map = {
            'sil': [0.0, 0.0, 0.0],      # 沉默
            'ppp': [0.8, 0.0, 0.8],      # p, b, m(闭唇)
            'fff': [0.2, 0.8, 0.2],      # f, v(上齿咬唇)
            'thh': [0.3, 0.5, 0.3],      # th
            'ddd': [0.5, 0.3, 0.5],      # t, d, n
            'err': [0.4, 0.4, 0.4],      # r
            'sss': [0.3, 0.3, 0.6],      # s, z
            'shh': [0.4, 0.4, 0.7],      # sh, ch, j
            'aaa': [0.9, 0.0, 0.9],      # a
            'eee': [0.6, 0.0, 0.6],      # e
            'iii': [0.4, 0.0, 0.4],      # i
            'ooo': [0.2, 0.8, 0.2],      # o
            'uuu': [0.3, 0.6, 0.3],      # u
        }
        
        # 口型参数:[张嘴、噘嘴、咧嘴]
    
    def generate_lipsync(self, text, audio_duration):
        """
        从文本生成唇形序列
        """
        # 1. 文本→音素
        phonemes = self.text_to_phonemes(text)
        
        # 2. 音素→口型(viseme)
        visemes = [self.phoneme_to_viseme(p) for p in phonemes]
        
        # 3. 时间分配
        total_phonemes = len(phonemes)
        duration_per_phoneme = audio_duration / total_phonemes
        
        # 4. 生成口型序列
        lip_sequence = []
        for viseme in visemes:
            num_frames = int(duration_per_phoneme / 0.016)
            for _ in range(num_frames):
                lip_sequence.append(viseme)
        
        return lip_sequence
    
    def text_to_phonemes(self, text):
        """
        文本→音素转换
        可以使用 g2p_en 等库
        """
        # 简化示例
        phoneme_dict = {
            'hello': ['hh', 'ax', 'l', 'ow'],
            'world': ['w', 'er', 'l', 'd'],
            'robot': ['r', 'ow', 'b', 'aa', 't'],
        }
        
        phonemes = []
        for word in text.lower().split():
            if word in phoneme_dict:
                phonemes.extend(phoneme_dict[word])
            else:
                phonemes.extend(['sil'])  # 未知词
        
        return phonemes
    
    def phoneme_to_viseme(self, phoneme):
        """
        音素→口型转换
        """
        # 音素分组到 viseme
        groups = {
            'ppp': ['p', 'b', 'm'],
            'fff': ['f', 'v'],
            'thh': ['th'],
            'ddd': ['t', 'd', 'n'],
            'err': ['r'],
            'sss': ['s', 'z'],
            'shh': ['sh', 'ch', 'j'],
            'aaa': ['aa', 'ah'],
            'eee': ['eh', 'ae'],
            'iii': ['iy', 'ih'],
            'ooo': ['ao', 'aw'],
            'uuu': ['uw', 'uh'],
        }
        
        for viseme, phoneme_list in groups.items():
            if phoneme in phoneme_list:
                return self.viseme_map[viseme]
        
        return self.viseme_map['sil']

四、表情识别

4.1 面部表情识别(FER)

深度学习方案

import torch
import torch.nn as nn
import torchvision.models as models

class FacialExpressionRecognizer(nn.Module):
    """
    面部表情识别模型
    """
    def __init__(self, num_classes=7):
        super().__init__()
        
        # 使用预训练 ResNet
        self.backbone = models.resnet18(pretrained=True)
        
        # 替换最后的全连接层
        num_features = self.backbone.fc.in_features
        self.backbone.fc = nn.Sequential(
            nn.Dropout(0.5),
            nn.Linear(num_features, 256),
            nn.ReLU(),
            nn.Linear(256, num_classes)
        )
        
        # 7 类基本表情
        self.classes = ['angry', 'disgust', 'fear', 'happy', 'sad', 'surprise', 'neutral']
    
    def forward(self, x):
        return self.backbone(x)
    
    def predict(self, face_image):
        """
        预测表情
        """
        self.eval()
        
        # 预处理
        input_tensor = self.preprocess(face_image)
        
        with torch.no_grad():
            output = self.forward(input_tensor)
            probabilities = nn.functional.softmax(output, dim=1)
            
            # 获取预测
            confidence, predicted = torch.max(probabilities, 1)
            
            return {
                'expression': self.classes[predicted.item()],
                'confidence': confidence.item(),
                'probabilities': dict(zip(self.classes, probabilities[0].tolist()))
            }
    
    def preprocess(self, image):
        """
        预处理
        """
        # 人脸检测、对齐、归一化
        # 使用 dlib 或 MTCNN
        pass

# 训练
def train_fer_model():
    """
    训练表情识别模型
    """
    # 数据集:FER2013, AffectNet, RAF-DB
    dataset = FER2013Dataset()
    
    model = FacialExpressionRecognizer()
    criterion = nn.CrossEntropyLoss()
    optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
    
    # 训练循环
    for epoch in range(50):
        for images, labels in dataset:
            outputs = model(images)
            loss = criterion(outputs, labels)
            
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()

4.2 多模态情感识别

融合方案

class MultimodalEmotionRecognizer:
    """
    多模态情感识别
    融合面部、语音、文本
    """
    def __init__(self):
        # 各模态模型
        self.face_model = FacialExpressionRecognizer()
        self.voice_model = VoiceEmotionRecognizer()
        self.text_model = TextSentimentAnalyzer()
        
        # 融合权重
        self.weights = {
            'face': 0.5,
            'voice': 0.3,
            'text': 0.2
        }
    
    def recognize(self, face_image, audio, text):
        """
        多模态情感识别
        """
        # 各模态识别
        face_result = self.face_model.predict(face_image)
        voice_result = self.voice_model.predict(audio)
        text_result = self.text_model.predict(text)
        
        # 融合
        fused_probabilities = {}
        for emotion in self.face_model.classes:
            p_face = face_result['probabilities'].get(emotion, 0)
            p_voice = voice_result['probabilities'].get(emotion, 0)
            p_text = text_result['probabilities'].get(emotion, 0)
            
            # 加权融合
            fused = (
                self.weights['face'] * p_face +
                self.weights['voice'] * p_voice +
                self.weights['text'] * p_text
            )
            fused_probabilities[emotion] = fused
        
        # 归一化
        total = sum(fused_probabilities.values())
        fused_probabilities = {k: v/total for k, v in fused_probabilities.items()}
        
        # 最终预测
        predicted = max(fused_probabilities, key=fused_probabilities.get)
        
        return {
            'emotion': predicted,
            'confidence': fused_probabilities[predicted],
            'probabilities': fused_probabilities,
            'modality_results': {
                'face': face_result,
                'voice': voice_result,
                'text': text_result
            }
        }

五、应用案例

5.1 Sophia(Hanson Robotics)

面部系统

Sophia 面部表情系统

├── 驱动方式
│   ├── 电机驱动 × 62
│   └── 硅胶皮肤

├── 自由度
│   ├── 眉部:6 DOF
│   ├── 眼部:8 DOF(含眼球)
│   ├── 鼻部:2 DOF
│   ├── 口部:20 DOF
│   ├── 脸颊:10 DOF
│   ├── 颈部:8 DOF
│   └── 其他:8 DOF

├── 性能
│   ├── 表情数量:50+
│   ├── 响应时间:100 ms
│   └── 识别率:90%+

└── 应用
    ├── 人机交互
    ├── 媒体露面
    └── 研究平台

5.2 Ameca(Engineered Arts)

面部系统

Ameca 面部表情系统

├── 驱动方式
│   ├── 电机驱动 × 40+
│   └── 模块化设计

├── 特点
│   ├── 超逼真表情
│   ├── 微表情支持
│   ├── 语音同步
│   └── 实时响应

├── 性能
│   ├── 刷新率:60 Hz
│   ├── 精度:0.1°
│   └── 延迟:<50 ms

└── 应用
    ├── 客户服务
    ├── 虚拟助手
    └── 影视制作

5.3 小米 CyberOne

面部系统

CyberOne 面部表情系统

├── 驱动方式
│   ├── 显示方案(OLED 屏幕)
│   └── 分辨率:128×128

├── 特点
│   ├── 可编程表情
│   ├── 动画播放
│   └── 情感识别反馈

├── 性能
│   ├── 表情数量:100+
│   ├── 响应时间:<10 ms
│   └── 成本:低

└── 应用
    ├── 家庭陪伴
    ├── 展示导览
    └── 教育

六、总结

6.1 核心要点

  1. 面部是情感窗口:55% 情感信息通过面部传递
  2. 驱动方式多样:电机精确、气动柔顺、显示灵活
  3. FACS 是标准:基于动作单元的表情描述
  4. 多模态识别:面部 + 语音 + 文本融合
  5. 成本待降低:从$50,000 降至$5,000

6.2 技术成熟度

技术成熟度商用时间
电机驱动⭐⭐⭐⭐已商用
表情识别⭐⭐⭐⭐已商用
语音同步⭐⭐⭐⭐已商用
气动驱动⭐⭐⭐研究中
微表情⭐⭐研究中

6.3 长期展望

面部表情技术正朝着更逼真、更自然、更低成本的方向发展:

  • 短期:电机驱动普及,表情识别成熟
  • 中期:人工肌肉驱动,微表情支持
  • 长期:神经接口,直接情感读取

面部表情是人形机器人**从”机器”到”伙伴”**的关键桥梁,将直接决定人机交互的自然度和情感连接。


参考资料


分享这篇文章到:

上一篇文章
Go 微服务架构实战
下一篇文章
表设计与范式理论