用Tensorflow.js让蒙娜丽莎的效果栩栩如生

2020-09-26 01:03:34

都市传说说,当你在房间里走来走去时,蒙娜丽莎的眼睛会跟着你。这就是众所周知的“蒙娜丽莎效应”。为了好玩,我最近编写了一个交互式数字肖像,通过你的浏览器和网络摄像头将这种现象栩栩如生地呈现出来。

该项目的核心利用了TensorFlow.js、深度学习和一些图像处理技术。大意是这样的:首先,我们必须生成蒙娜丽莎头部的一系列图像,眼睛从左向右凝视。从这个池中,我们将根据观众的位置连续选择并实时显示单个帧。

在这篇文章中,我将详细介绍该项目的技术设计和实现。

图像动画是一种技术,它允许人们通过驾驶视频来操纵静止图像。使用基于深度学习的方法,我能够生成一个非常令人信服的蒙娜丽莎凝视的动画。

具体地说,我使用了Aliaksandr Siarohin等人发布的一阶运动模型(FOMM)。2019年。在很高的层次上,该方法由两个模块组成:一个用于运动提取,另一个用于图像生成。运动模块从驾驶视频中检测关键点和局部仿射变换。然后,将这些值在连续帧之间的差异用作预测密集运动场的网络的输入,以及指定需要修改或上下文推断的图像区域的遮挡遮罩。然后,图像生成网络检测面部地标,并根据运动模块的结果产生最终输出--经过扭曲和内绘的源图像。

我特别选择了Fomm,因为它易于使用。这个领域以前的模型是“特定于对象的”,这意味着它们需要对象的详细数据来进行动画处理,而Fomm对此的操作是不可知的。更重要的是,作者发布了一个开源的、开箱即用的实现,带有预先训练的面部动画权重。正因为如此,将模型应用于蒙娜丽莎变得出人意料地简单:我只需将回购克隆到Colab笔记本中,制作一段我眼睛四处移动的驾驶短片,然后将其与La Gioconda头部的屏幕截图一起输入到模型中。由此产生的电影非常出色。由此,我最终只采样了33张图片来构成最终的动画。

虽然我可以为我的项目重新训练模型,但我决定在Siarohin权重的限制范围内工作,以避免否则需要的时间和计算资源。然而,这意味着最终的帧被固定在比预期更低的分辨率,并且只由受试者的头部组成。但由于我希望最终的视觉效果包括整个蒙娜丽莎--包括手、躯干和背景--我的计划是简单地将输出的头框叠加到这幅画的图像上。

然而,这也带来了一系列挑战。如果您查看上面的示例,您会注意到模型的较低分辨率输出--再加上由于Fomm的扭曲过程造成的一些细微的附带背景变化--导致头部框架在视觉上突出。换句话说,很明显,这只是一张图片叠加在另一张图片上。为了解决这个问题,我用Python进行了一些图像处理,以便将头部图像“混合”到底层图像中。

首先,我将头部框架的大小调整为其原始分辨率。在此基础上,我使用这些模糊像素和底层图像中相应像素的加权平均值创建了一个新帧,其中头部帧中像素的权重--或alpha--随着其远离中点而降低。

确定α的函数改编自2D Sigmoid,并表示为:

其中j确定Logistic函数的斜率,k是拐点,m是输入值的中点。如图所示,该函数如下所示:

在我将上述过程应用于动画集中的所有33个帧之后,产生的每个叠加对不知情的人来说都是一幅图像:

在这一点上,剩下的就是确定如何通过网络摄像头跟踪用户并显示相应的画面。

自然,我求助于TensorFlow.js来完成这项工作。该库提供了一组相当健壮的模型来检测给定视觉输入的人的存在,但是经过一些研究和思考,我选择了BlazeFace作为我的方法。

BlazeFace是一个基于深度学习的对象识别模型,可以检测人脸和面部地标。它接受过使用移动相机输入的专门培训。这对我的用例很有效,因为我预计大多数观众都会以类似的方式使用他们的网络摄像头--头部在框架内,面向前方,相当靠近摄像头--无论是通过他们的移动设备还是在他们的笔记本电脑上。

然而,在选择这款机型时,我首先考虑的是它超乎寻常的检测速度。为了让这个项目令人信服,我需要能够实时运行整个动画,包括面部识别步骤。BlazeFace采用单镜头检测(SSD)模型,这是一种基于深度学习的目标检测算法,它同时提出边界框并在网络的一次前向传递中检测目标。BlazeFace的轻型探测器能够以每秒200帧的速度识别面部地标。

确定了模型后,我然后编写代码,将用户的网络摄像头数据持续传输到BlazeFace。每次运行时,模型都会输出一组面部地标及其对应的2D坐标位置。利用这一点,我通过计算眼睛之间的中点来近似计算脸部中心的X坐标。

最后,我将结果映射到0到32之间的整数。您可能还记得,这些值分别表示动画序列中的一个帧--0表示蒙娜丽莎眼睛向左,32表示蒙娜丽莎眼睛向右。从那时起,只需在屏幕上显示框架即可。

您可以在monalisaffects t.com上操作该项目。要关注更多我的工作,请随时查看我的个人网站Github或Twitter。

感谢Andrew Fu阅读这篇文章并为我提供反馈,感谢Nick Platt倾听他对前端bug的思考,感谢Jason Mayes和Google的其他团队成员在扩展和扩大这个项目方面所做的工作。