Notifications
Article
利用深度学习模型控制 VTuber 的表情
Updated 10 months ago
1.3 K
5
在 OpenCV 中利用深度学习模型捕捉表情
上次我们演示了通过 OpenCV for Unity 进行人脸识别进而控制卡通人物,但是之前的例子只能识别头部的转动,以及眼睛嘴巴的开闭,我们并不能识别人的表情。在 iPhone X 借助深度摄像头已经能识别脸部肌肉的年代,OpenCV 的功能这么有限实在说不过去。有没有办法用 OpenCV 来识别脸部表情,最好还有现成的 Unity 代码呢?一找还真找到了。
本文主要参考下文,原文为日文,但并不影响我们借用其中的代码。
https://qiita.com/utibenkei/items/adc7f526d629bdfc41fc

1. 测试表情检测

我们先来测试一下代码能不能用。将上文中的 OpenCVDnnEmotionFerPlusExample 以及 OpenCVDnnModuleExampleBase 两段代码添加到我们的项目中,再从下面的地址下载 model 文件,解压放在我们的 StreamingAssets 目录中。
https://github.com/onnx/models/tree/master/vision/body_analysis/emotion_ferplus
另外我们可以从 https://github.com/ebarsoum/FERPlus 截取几个表情用于测试,截取的表情同样放在 StreamingAssets 目录中。
以上准备完成后,新建场景,添加一个 GameObject,并在之上添加 OpenCVDnnEmotionFerPlusExample。在 Input 和 Model 中分别填入用于测试的表情图片以及表情 model 的地址,在 Classes List 中则填入该模型可以识别的八种表情。
最下方的 UI 段落中需要填入一些控件用于输出信息,与核心逻辑无关。
运行之后,我们就能看到程序识别的表情了。比如这个是 surprise,
这个是 anger。
把识别出的表情和 blendshape 结合起来,(理论上)我们就能通过 OpenCV 控制 VTuber 的表情了。

2. 修改 VRMCVVTuberExample 为读取视频文件

我们将使用曾经用过的 VRMCVVTuberExample 来实现控制 VTuber 的功能。原来的 VRMCVVTuberExample 是从摄像头读取图像信息,我们这次为了测试方便,改成从本地视频文件读取图像。做法可以参考 VideoCaptureCVVTuberExample。完成后应该是这样子。

3. 在 VRMCVVTuberExample 中加入表情检测

接下去我们要做的就是把 1 的功能加入 2 的场景中。我们可以在这里
https://github.com/fengkan/OpenCVDnnEmotionFerPlusExample
下载 DNNVTuber。DNNVTuber 就是上面 OpenCVDnnEmotionFerPlusExample 以及 OpenCVDnnModuleExampleBase 两段代码的合体,并且做了一些简化。
我们在 VRMCVVTuberExample 的场景中添加一个 GameObject,加上 DNNVTuber。其中关键的数值已经设置默认值,可以直接使用。为了测试方便,我们加入了一个 Text 变量,并将之设置为画面左上角的“Change Camera”按钮中的文本控件,用于显示当前的表情。
我们还需要修改 DlibFaceLandmarkGetter。这个类原来负责将图像材质交给 Dlib。我们在其中插入代码把图像传给 DNNVTuber,以便 DNNVTuber 读取每一帧,并识别出其中的表情。
public DNNVTuber dnnv; ... public override void UpdateValue () { ... if (rgbaMat != null) { ... if (dnnv != null) dnnv.ProcessImage(rgbaMat); ... } }
最后还需要修改 VRMFaceBlendShapeController,从 DNNVTuber 读取当前的表情,并且设置相应的 blendshape。
public DNNVTuber dnnv; ... protected override void UpdateFaceAnimation (List<Vector2> points) { ... if (dnnv) { switch (dnnv.getCurrentClass()) { case 1: // happiness blendShapeProxy.AccumulateValue(BlendShapePreset.Joy, 100); break; default: break; } } }
运行程序,我们能看到下面的结果。
如果加上 Blendshape 过渡,并且把置信度和 Blendshape 的数值挂钩的话,应该效果会更好。
以上修改之后的 DlibFaceLandmarkGetter 和 VRMFaceBlendShapeController 可以参照 https://github.com/fengkan/OpenCVDnnEmotionFerPlusExample 中的场景文件。
可惜,我们这里使用的 model 识别准确率不是很高,有兴趣的可以通过 https://microsoft.github.io/onnxjs-demo/#/emotion_ferplus 测试。虽然应该可以替换成其他 model,但是笔者还不知道如何实现,等以后知道了再介绍吧。
最后再放一遍以上代码的 GitHub,
https://github.com/fengkan/OpenCVDnnEmotionFerPlusExample
冯侃
www.sunnyview.tech - Programmer
11
Comments
袁亮
10 months ago
很酷 很好玩!
0
Unity社区
Staff
10 months ago
james Wang老师问个问题,对于软件开发出身的新手来说Audio这块的功能重要吗
@james Wang 感谢支持中文原创,恭喜获得新年开运大礼包,收货地址私信我哦~
0
jW
james Wang
10 months ago
冯侃不敢当,audio 如果不是大型游戏或者讲究沉浸感的游戏的话能基本使用应该就行了吧。
🤝
0
冯侃
10 months ago
www.sunnyview.tech
james Wang老师问个问题,对于软件开发出身的新手来说Audio这块的功能重要吗
不敢当,audio 如果不是大型游戏或者讲究沉浸感的游戏的话能基本使用应该就行了吧。
0
jW
james Wang
10 months ago
老师问个问题,对于软件开发出身的新手来说Audio这块的功能重要吗
1