深度学习口型驱动Visemenet使用小结

说明

我前一篇博客《使用共振峰提取元音音素/从声音生成口型动画》探索了使用共振峰分析元音,然后从元音音素映射到视位的口型驱动方案。当时我就在想,如果能用深度学习法方法从音频直接生成音素流,然后转换成对应视位,不就很容易做口型动画了吗。通过网络检索,发现Visemenet这个方案就是我要的,而且被引用还蛮多的。算是用深度学习生成音素的经典文章。通过阅读论文和代码,我初步熟悉了它的思路。这里来纪录下。

什么是JALI

JALI是英文单词下巴(JAW)和嘴唇(LIP)的合并简写,也是一个动画工具的名字,他们的官网是:https://jaliresearch.com/

看官网资料,他们主要是做口型动画的,他们的主要方法和概念在论文《JALI: An Animator-Centric Viseme Model for Expressive Lip Synchronization》里有介绍。他们通过观察发现,人们发音时的动作有两个重要维度,一是下巴骨骼的运动,二是嘴部肌肉的运动。而不同的说话"风格",可以通过调整这两个维度从而捕捉到更有表达力的口型。
比如同一个人用不同的情绪来发同一个音素,其口型差距巨大。不同的发音方法对应的嘴唇宽度和下巴位移量都不一样。
在这里插入图片描述
在JALI的坐标轴中,五种风格的发音分布如下。其横坐标是下巴位移,纵坐标是嘴唇形变。
在这里插入图片描述
当然,除了下巴和嘴唇宽度,正常的视位口型还是需要的。
JALI的论文中貌似是使用TTS软件来识别音素,使用算法将音素和音频对齐,然后根据总结的一些协同发音的规则来制作口型的动画。

JALI技术已经在大型RPG游戏《赛博朋克2077》中有了实际运用。游戏十余种本地化配音中的每一个字,都通过JALI技术实现了从语音到面部动画与口型的同步。

但是JALI的工作流还依赖人工总结的规则,需要手工介入调整。一种更自然的方案就是让深度学习来学习音素权重及曲线,这就是Visemenet的工作。

Visemenet

Visemenet主要是用深度学习的方法端到端生成JALI绑定模型口型的参数,较少人员的介入。
JALI的论文最后面,它说它使用的音素和苹果的开发文档里一致,我搜索到苹果的因素定义,不知道有多少个。Visemenet使用了因素组,因为多个因素对应的视位口型差不多,就将它们分为一类,减少动画建模的工作量。Visemenet使用了20个音素组:
在这里插入图片描述
此外,Visemenet还会使用人脸关键点作为监督。整体流程如下
在这里插入图片描述
可以看到,输入就是音频,经过LSTM会生成因素组和关键点的表征,这些表征和音频数据组合在一起,最后再输出因素分类,音素权重(类似动画曲线)及JA和LI。

代码使用

关键点动画效果

github上有Visemenet第一作者开源的一份代码yzhou359/VisemeNet_tensorflow,但是代码是tf1.1版本的,很难搭环境。github上有人将它移植到tf2.的环境中,并提供了从原作者仓中冻结的模型:junhwanjang/visemenet-inference

我主要使用junhwanjang/visemenet-inference来体验使用的。体验过程中我将模型中间过程的关键点做成了视频,我传到了b站上,效果如下:

https://www.bilibili.com/video/BV19t421c777/?vd_source=8abb7f0122649239c41b4c8acf458e47
关键点的布局如下:在这里插入图片描述
整体上来说,效果不是很好。为啥不好,我后面会分析。

推理代码流程

下面以一份33.45秒的视频的处理流程为例,接一下我理解的Visemenet的代码推理流程。它的采样率是16K,采样总数535200。

音频特征提取

使用python_speech_features工具包提取了logfbank, mfcc, ssc这三种特征后拼接在一起,这三种特征的帧步都是10ms,提取维度分别是26,13和26,拼接后最后一维是65.

音频特征提取完,变成了形状为(3344, 65)的特征。

推理前的其它处理

进入网络前,还需要进行正则化和按照24的宽度进行窗口重排数据,最终音频数据的形状变为(3344, 8, 195),同时还要读取人脸关键点的基准位置,形状为(3344, 76)

推理

网络的输入数据除了音频特征和人脸关键点,还有phase 和dropout ,推理时这两个数据默认为0

		x = self.graph.get_tensor_by_name('input/Placeholder_1:0')  #音频信号
        x_face_id = self.graph.get_tensor_by_name('input/Placeholder_2:0') #人脸关键点默认位置
        phase = self.graph.get_tensor_by_name('input/phase:0')  # 0
        dropout = self.graph.get_tensor_by_name('net1_shared_rnn/Placeholder:0') # 0

        ## Output nodes
        v_cls = self.graph.get_tensor_by_name('net2_output/add_1:0')
        v_reg = self.graph.get_tensor_by_name('net2_output/add_4:0')
        jali = self.graph.get_tensor_by_name('net2_output/add_6:0')
        land = self.graph.get_tensor_by_name("net1_output/add_2:0")  #第一阶段关键点,这是我自己加的
        pho = self.graph.get_tensor_by_name("net1_output/net1_pho_relu:0")  #第一阶段音素,这是我自己加的

        print("---------------predict_outputs 6---------------")
        with tf.compat.v1.Session(graph=self.graph) as sess:
            pred_v_cls, pred_v_reg, pred_jali, pre_land, pre_pho = sess.run(
                [v_cls, v_reg, jali, land, pho],
                feed_dict={
                    x: batch_x, 
                    x_face_id: batch_x_face_id,
                    dropout: 0, phase: 0
                    }
            )
            pred_v_cls = self.sigmoid(pred_v_cls)

为了输出第一阶段的因素组特征和人脸关键点,我加了两行代码。需要注意的是pho的形状是(3344, 256),并不是20个因素组的分类。我前面制作的关键点的动画就是用pre_land输出的结果制作的。

输出

输出的tensor有3个

pred_v_cls.shape:(3312, 20)
pred_v_reg.shape:(3312, 20)
pred_jali.shape:(3312, 2)

其中pred_v_cls表示音素组的分类概率,pred_v_reg表示音素的权重曲线,用来制作动画。pred_jali表示下巴和嘴唇的变形权重。
注意这里第一维少了32(从3344变为3312),我试了两段音频都是这个结果,不清楚是什么原因。这部分数据对应时间是320ms。
这里数据的维度和上面框架图中的29d对不上。

后处理及整体效果

后处理函数会对pred_v_cls、pred_v_reg和pred_jali进行多次滤波和平滑,最终得到一个形状为(3312, 22)的数据作为最终结果,第二维的前2个表示JA和LI的权重,后20个表示20个因素组的曲线变化。
我将JALI和音素组的曲线画出来了,可以发现效果并不好。其中JA和LI的权重基本是平的。
在这里插入图片描述
20个因素组,基本只有4-5个音素在一直表达,其它的都基本为0.通过网络中间生成的关键点来生成视频的效果也不是很好,所以我对Visemenet开源的模型效果表示不很满意。
在这里插入图片描述

小结

写累了,就这样吧。本来打算用visemenet做动画的,还不如我的共振峰的效果。

参考资料

JALI: An Animator-Centric Viseme Model for Expressive Lip Synchronization

VisemeNet: Audio-Driven Animator-Centric Speech Animation

语音生成口型与表情技术的演进与未来

Visemenet作者开源:yzhou359/VisemeNet_tensorflow

Visemenet可以运行的例子tf2.0:junhwanjang/visemenet-inference

使用共振峰提取元音音素/从声音生成口型动画

JALI官网:https://jaliresearch.com/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/586322.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Vue项目打包APK----Vue发布App

时隔多年我又来跟新了,今天给大普家及下前端Vue傻瓜式发布App,话不多说直接上干货。 首先准备开发工具HBuilder X,去官网直接下载即可,算了直接给你们上地址吧HBuilderX-高效极客技巧。 打开软件,文件-->新建--&g…

ARM学习(27)链接库依赖学习(二)dlopen failed:library xxxx.so

笔者继续学习一下链接的依赖库。 1、起因 Android下面需要需要一个日志解码库,所以笔者就编译了一个parse.so来进行解码, 编译器:Clang,基于llvm后端的编译器平台:交叉编译,linux -> aarch64 linux An…

Java | Leetcode Java题解之第62题不同路径

题目&#xff1a; 题解&#xff1a; class Solution {public int uniquePaths(int m, int n) {long ans 1;for (int x n, y 1; y < m; x, y) {ans ans * x / y;}return (int) ans;} }

Python+PYGObject/PYGtk+CSS样式--2024python示例

隔久点不用老是会忘&#xff0c;留个笔记。。 PythonPYGObject/PYGtk&#xff0c;加载 CSS 样式的演示代码 demo 运行的效果截图&#xff1a; #!/usr/bin/env python3 import sys import gigi.require_version("Gtk", "3.0") from gi.repository import …

Web APIs 学习归纳5--- BOM浏览器对象

前面几节主要针对DOM进行了学习&#xff0c;现在开始新的内容的学习---DOM浏览器对象。 DOM是更注重页面&#xff08;document&#xff09;内容的设计&#xff0c;但是BOM不仅限于页面&#xff08;document&#xff09;的设计&#xff0c;而是更加全面包括页面的刷新&#xff0…

【小迪安全2023】第59天:服务攻防-中间件安全CVE复现lSApacheTomcatNginx

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【Java、PHP】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收…

Taro引入echarts【兼容多端小程序(飞书/微信/支付宝小程序)】

近期接到公司新需求&#xff0c;开发飞书小程序&#xff0c;并且原型中含有大量的图表&#xff0c;本想使用飞书内置图表组件 —— chart-space&#xff0c;但官方表示已经停止维护了&#xff0c;无奈之下&#xff0c;只能另寻他路&#xff0c;于是乎&#xff0c;图表之王&…

Content type ‘application/json;charset=UTF-8‘ not supported异常的解决过程

1.首先说明开发场景 *就是对该json格式数据传输到后台 后台实体类 import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.Data; import org.sp…

CSS移动端弹性布局

一级标题 二倍图 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>背景图片</title><styl…

LLM系列(4):通义千问7B在Swift/DeepSpeed上微调秘诀与实战陷阱避坑指南

LLM系列(4):通义千问7B在Swift/DeepSpeed上微调秘诀与实战陷阱避坑指南 阿里云于 2023年8 月 3 日开源通义千问 70 亿参数模型,包括通用模型 Qwen-7B 以及对话模型 Qwen-7B-Chat,这也是国内首个开源自家大模型的大厂。在诸多权威大模型能力测评基准上,如 MMLU、C-Eval、…

VSCode 配置 CMake

VSCode 配置 C/C 环境的详细过程可参考&#xff1a;VSCode 配置 C/C 环境 1 配置C/C编译环境 方案一 如果是在Windows&#xff0c;需要安装 MingW&#xff0c;可以去官网(https://sourceforge.net/projects/mingw-w64/)下载安装包。 注意安装路径不要出现中文。 打开 windows…

备忘录模式(行为型)

目录 一、前言 二、备忘录模式 三、总结 一、前言 备忘录模式(Memento Pattern&#xff09;是一种行为型设计模式&#xff0c;在不破坏封装性的前提下&#xff0c;捕获一个对象的内部状态&#xff0c;并在该对象之外保存这个状态&#xff0c;这样可以在之后将该对象恢复到原…

搭建和配置Stable Diffusion环境,超详细的本地部署教程

跃然纸上的创意、瞬息万变的想象&#xff0c;Stable Diffusion以AI的力量赋予您无限创作可能。在这篇详尽的本地部署教程中&#xff0c;我们将携手走进Stable Diffusion的世界&#xff0c;从零开始&#xff0c;一步步搭建和配置这个强大的深度学习环境。无论您是热衷于探索AI艺…

Notes for the missing semester. Useful and basic knowledge about Linux.

The Shell Contents The first course is to introduce some simple commands. I’ll list some commands that I’m not familiar with: # --silent means dont give log info, # --head means we only want the http head. curl --head --silent bing.com.cn# cut --deli…

(7)快速调优

文章目录 前言 1 安装脚本 2 运行 QuikTune 3 高级配置 前言 VTOL QuikTune Lua 脚本简化了为多旋翼飞行器的姿态控制参数寻找最佳调整的过程。 脚本会缓慢增加相关增益&#xff0c;直到检测到振荡。然后&#xff0c;它将增益降低 60%&#xff0c;并进入下一个增益。所有增…

smac 路径优化器分析——距离成本和代价地图成本分析

参考 泰勒级数直观详解 前向差分&#xff0c;后向差分&#xff0c;中心差分 相关文章 smac 路径优化器分析——平滑度成本分析 smac 路径优化器分析——曲率成本分析 距离成本 距离成本函数 用优化后的点与原路径点的欧氏距离的平方作为成本。 下图中蓝色原点是原路径点…

java-springmvc 01 补充 javaweb 三大组件Servlet,Filter、Listener(源码都是tomcat8.5项目中的)

01.JavaWeb三大组件指的是&#xff1a;Servlet、Filter、Listener,三者提供不同的功能 这三个在springmvc 运用很多 Servlet 01.Servlet接口&#xff1a; public interface Servlet {/*** 初始化方法* 实例化servlet之后&#xff0c;该方法仅调用一次 * init方法必须执行完…

【MySQL | 第九篇】重新认识MySQL锁

文章目录 9.重新认识MySQL锁9.1MySQL锁概述9.2锁分类9.2.1锁的粒度9.2.2锁的区间9.2.3锁的性能9.2.4锁的级别 9.3拓展&#xff1a;意向锁9.3.1意向锁概述9.3.2意向锁分类9.3.3意向锁作用&#xff08;1&#xff09;意向锁的兼容互斥性&#xff08;2&#xff09;例子1&#xff08…

C++ | Leetcode C++题解之第61题旋转链表

题目&#xff1a; 题解&#xff1a; class Solution { public:ListNode* rotateRight(ListNode* head, int k) {if (k 0 || head nullptr || head->next nullptr) {return head;}int n 1;ListNode* iter head;while (iter->next ! nullptr) {iter iter->next;n…

CTFHub-Web-SQL注入

CTFHub-SQL注入-WP 1.整数型注入 1.题目说输入1&#xff0c;先将1输入查看结果 2.接着输入4-1&#xff0c;发现输出的结果为4-1&#xff0c;判定存在整数型注入 3.查询字段数&#xff0c;出现了回显&#xff0c;判断这里的字段数为2 1 order by 24.判断注入点在2的位置&…
最新文章