Appearance
基于 Mediapipe 的面部捕捉算法
把 Mediapipe 每帧输出的 478 个原始特征点,按面部区域归纳成语义化、抗抖动的 BlendShape 数据,让普通摄像头直接驱动虚拟人面部。
技术问题
摄像头加 Mediapipe 只能回答一个问题:这一帧人脸上的 478 个点各自在什么坐标。而虚拟人模型要的是另一种数据——BlendShape 通道权重,比如「眨眼 0.6」「张嘴 0.3」,取值范围 0 到 1。
中间缺的这一层就是特征点归纳算法:怎么从一堆点位坐标算出语义化的表情权重。当时市面上没有开源的、基于 Mediapipe 点位图的归纳实现——要用 Mediapipe 做面捕,这一层只能自己写。
现有方案不足
- 直接线性映射:把点位距离直接按比例映射到 BlendShape,不同人脸的五官比例差异大,数值范围漂移,基本不可用。
- 原始解算不平滑:相邻帧的特征点检测天然带噪声,不做滤波直接驱动模型,面部会高频抖动。
- 商用 SDK 绑定自家生态:ARKit 这类方案自带归纳能力,但绑定自家协议和平台,无法直接用在 Mediapipe 链路上。
核心思路
按面部区域拆分归纳模块,每个模块只消费自己区域的特征点,输出该区域语义化的 BlendShape 值;所有模块的输出汇总成原始 BS 数据集,统一过滤波后再交给驱动层。
mermaid
flowchart LR
A["相机模块<br>每帧输出人脸纹理"] --> B["Mediapipe 推理<br>输出 478 个特征点"]
B --> C["归纳模块<br>眉 / 眼 / 嘴 / 眼珠"]
C --> D["原始 BlendShape<br>数据集"]
D --> E["滤波模块<br>低通 + 卡尔曼"]
E --> F["CompatibleFaceBlendShape<br>稳定 BS 数据"]
F --> G["模型驱动层<br>面部迁移"]关键实现
区域归纳
以眨眼为例:取眼部关键特征点与基准特征点(即眨眼通道值为 0、眼睛完全睁开时的未变化状态)之间的距离关系,经眨眼函数、分段函数和 lerp 处理,输出 0-1 的眨眼幅度。眉毛、嘴巴、眼珠模块同理,各自取本区域的关键点做推导,再持续调参收敛到可用效果。
工程拆分
- UnityMediapipePlugin:管理相机纹理输出,托管 Mediapipe 框架,产出特征点数据集。
- MediapipeAdaptor:承载归纳算法和滤波模块,把特征点处理成稳定平滑的 BS 数据集。
- 驱动层:业务代码,按模型自身的 BlendShape 协议消费数据,与解算链路完全解耦。
可移植性
归纳算法只依赖点位图的语义定义(哪个编号是眼角、哪个是嘴角),不依赖 Mediapipe 本身。其他面捕引擎只要点位定义与 Mediapipe 一致,同一套归纳算法可以直接复用。
应用场景
- 虚拟直播 PC 端:摄像头面捕实时驱动虚拟主播。
- AR 头套开播:移动端复用同一条链路。
- 已落地于虚拟直播姬 PC 版、AR 头套开播 PC 版、虚拟直播姬移动端。
关联案例
- Mediapipe 面捕解算器:解算链路的工程实现。
- CompatibleFaceBlendShape 协议:本算法输出的数据协议。
- BlendShape 基本表情转换特殊表情:在基础 BS 之上继续推导特殊表情。