怎么用Tensorflow+Docker+CloudRun,制作你的专属特效?

当我们观看抖音短视频时,亦或是和亲朋好友视频聊天时,我们总会看到一些有趣的特效功能,这些功能会智能的基于我们的五官、表情,绘制出种种神奇的特效,让我们不禁感叹到:“amazing!”.

(图片来自抖音特效官网截图)

那么你有没有想过,这些特效是如何实现的?我们能不能创作一个自己专属的特效呢?以致于应用,可以供大家一起赏玩呢?

觉得很难?no no no

事实上比你想象的还要简单。

废话少说,show me the code. 让我们现在就开始试试看!

首先设想一个这样的怪物——“它的左眼冒着红光,死死的凝视着你,就如同你凝视着深渊……”

开个玩笑,假设我们想要实现这个最终目标:

-开发一个应用,这个应用通过摄像头捕获到你的脸,然后自动识别到你的眼睛,并且让你的眼睛冒出红光。

那么在这之前,就要先来完成一个小目标:

-应用通过摄像头捕获到你的脸,然后自动识别到你的眼睛

朋友朋友,桥豆麻袋,先等一步——

这件事情,还真没有你想象的那么难。

基于谷歌开放的 tensorflow.js 我们可以轻松在网页/手机移动端,完成机器学习任务,且谷歌提供了大量预训练模型,基于这些应用场景丰富、功能强大的模型,我们能随时开箱即用。

而这些开箱即用的模型中,就有我们所需的模型——人脸特征点监测模型。

简单来说,这个模型输入一张带有人脸的图像,它会自动识别人脸,并且在人脸上标注多达436个的3D特征点(x轴, y轴, z轴)。

这些3D特征点,分别对应了人脸中的一些重要特征,例如:脸颊/嘴唇/鼻子/眼睛……当然一个特征可能有数十个点组成,例如眼睛就可能包括几十个特征点,具体如下图所示:

可以看到,这些特征点非常的细致,而且最重要的是,它非常准确地标识了眼睛的位置。

所以我们的工作就变得异常简单:

-应用这个模型

-开启我们的摄像头并把图像逐帧传递给模型

-从模型预测的结果中提取特征坐标数据,例如我们的眼睛

应用模型的方式很多,我们既可以使用script tag直接引用谷歌的.js脚本文件,也可以通过yarn进行npm包的安装管理,哪种方式都可以。安装完毕后,就可以开始使用。

此处所应用模型为:@tensorflow-models/face-landmarks-detection

对于模型的使用,可以简述为如下三步骤:

其中加载模型部分,我们可以直接使用预设的模型,需要关注的就只有两部分内容:

  • 贯入数据(这里面也就是我们摄像头捕获的图像数据)
  • 解析结果(因为模型返回的结果很多,我们需要提取其中有用的信息)

在HTML中,我们可以通过navigator.mediaDevices.getUserMedia,来开启摄像头获得媒体流数据,然后绑定到一个video元素上。

接着直接在加载完毕的模型上,调用评估预测方法,并传入video元素即可,模型机会自动获取video传入的帧数据,并进行预测。

此处可能大家会比较疑惑,为什么要加载模型,为什么贯入数据后,就能返回带有特征坐标信息的点呢?这块对应的是人工智能?机器学习?不是说这个计算量特别大,特别麻烦吗?

的确,中间涉及的各种深度学习知识/逻辑十分复杂,但是基本原理很简单,下面做一个示例,帮助大家理解:

假设,我们有变量x,需要预测变量x对应的y值,并且基于此构建了一个简单的方程:y=ax+b .

上述我们已知的是自变量x,想要预测的是y,那么为了达成预测,就需要知道参数a,b分别是什么。

假如我们有一堆x&y,那么就可以找到一种方式,通过x,y来确定,能够基于x准确预测y的值的a,b。

上述提到的方式,就对应了诸多的机器学习算法,而通过输入大量的x,y值来找到a,b的过程,就是模型训练的过程。

对应到图片,则我们输入的x就变成了图片的数据,图片我们可以理解为一个个的像素点,每个像素点都是RGB三个值的累积,那么一个1920*1080像素的图片,也就可以表达为一个1920*1080*3=6220800——多达600w个点的集合,而一次训练,少的时候也需要涉及成千上万的图片。

可想而知,模型训练的过程计算量多么庞大,需要极其强大的计算能力。(当然,实际为了完成计算,会做非常多的处理,逻辑。)

但区别于训练,如果我们已经找到了合适的a,b,那么想要计算y时,则只需要把值代入公式即可,例如y=ax+b,这需要的计算能力,就简单多了。

所以对于人脸特征检测,我们所应用的是一个谷歌已经训练好的模型(计算量巨大的模型训练过程,谷歌已经帮我们做好),而我们在本地(电脑/手机)所进行的,就是简单的预测计算而已。

回归原主题,将视频数据贯入已经训练好的模型后,模型就会给我们预测的结果数据。例如:

可以看到,图中的数据以坐标的形式呈现了出来,这里我们主要使用x轴,y轴数据,也就是Array的前两项。

除了scaledMesh对应的坐标外,还有例如boundingBox——标识了所识别的人脸顶部左侧以及底部右侧的两个点,有了这两个点,就可以从图像中切割出人脸,并将其转化为模型所需的数据(这些过程都是自动的,我们所输入的就是图像数据。)

举个例子,我们提取出boundingBox的数据,处理后就可以用于canvas上画出框线来标识人脸,如下所示:

如上述视频所示,可以看到随着人脸的变动,所画的框线也在不停的重新绘制(其实也可以理解为我们针对输入的每一帧视频,又重新预测了人脸,并根据此重新获得标识点,画出了框线。)

而如果我们把预测的点位都标识出来,则如下所示:

确定了这些内容后,我们下一步就是提取眼部的特征,这部分数据可以直接在 annotations中获取,如下所示:

可以看到,输出的数据中十分详尽的标识了同类特征点。我们通过leftEyeLower0& leftEyeUpper0就基本可以定位眼睛的数据。

下图所示,就是leftEyeLower0&leftEyeUpper0的特征点构成,可以看到几乎非常完美的包裹了眼睛的位置。

确定了眼睛的位置,接下来可以做的操作就很多了。比如虚拟美瞳/口红试妆等等,不过我们的目的是创造冒着红光的眼睛!

那么接下来,该如何创造这样的眼睛呢?

我们可以通过canvas构建粒子系统模拟火焰燃烧效果,来实现这一目标。粒子系统是一种在计算机图形学中,用于表现模糊现象的常用技术,经常用来表现火焰/烟/水流等等。

例如火焰,我们就可以模拟为数量众多的粒子,向上不断运动,并在运动的过程中,不断缩小直至湮灭,当然为了真实,我们通常还会设置随机数,使得火焰在上升的过程中是不断摆动的。

如下图所示,一个包含了200个粒子,每帧左右浮动-3,3,上下浮动3,4的渲染效果。

为了方便理解,我们只保留1个粒子,则如下图所示,可以看到其实火焰的效果就是多个粒子的不规则运动。

理解了火焰粒子特效的原理,我们就可以为自己的眼睛施展魔法了,此处略过大段代码,来看一下最终效果。

我们也可以调整图层融合效果,让其变得更加多变。

完成了人眼的识别&DuangDuang的特效添加过程,此时我们已经可以在本地使用了,但怎么才能分享给小伙伴们,大家一起欢乐呢?

做成网页应用的形式,是一个很普适的好办法。但令人头疼的是,如果我们想要上线一个应用,那么可能还得需要一个服务器,在上面进行环境配置,进行部署,甚至还需要考虑性能问题等等……

那么有没有一种更加简单的方式呢?可以免除购买服务器,免除环境配置,免除balabala烦心事的方法呢?

肯定是有的,在这里我们使用的是Docker+Cloud Run的方式。

对Docker熟悉的朋友很多,通过Docker这种容器化的方式,我们可以快速的配置环境,而Cloud Run是谷歌云提供的一种全代管式,可快速/安全部署和托缩容器化应用。

也就是说,我们可以先在本地Docker中配置好程序,然后构建容器,直接把这个容器提供给Cloud Run,它就会帮助完成所有剩余的工作,包括服务器管理/环境配置/服务提供等等,然后提供给我们一条可访问的链接,接下来就可以把链接分享给其他小伙伴,供他们使用啦!

而且非常诱人的是,该服务只有在代码运行时,我们才需要付费,对于这种轻量应用来说,简直就是性价比至极。

详细来说,分为以下几个步骤:

1.在本地构建项目文件,比如index.html&index.js ,此处使用parcel进行了打包。

-构建出来的文件,我们放到了dist文件中。

2.构建Dockerfile 文件。Dockerfile是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明。

以下本次使用的 Dockerfile 文件:

里面的大致意思可以理解为,我们基于nginx:alpine的镜像,复制了本地的nginx配置文件到nginx的配置读取路径下,然后把dist/中的,也就是通过parcel打包的输出文件,复制到nginx指定的读取目录下,稍后我们就可以通过nginx以路径的形式访问相应的文件。

3.使用GCP build来构建容器并上传至Container Registry,我们一般使用gcloud命令来构建容器,可以非常方便在本地使用gcloud命令,也可以直接在cloud shell中直接使用。

上传的文件如上所示。

4.在Cloud Run中构建服务

这里面的容器映象网址,就是Container Registry中存储的容器地址。

如果容器构建无误,服务就会开启,并提供给你一个可访问的链接

至此,你就完成了应用的上线。分享网址,你就可以和小伙伴一起共享你的专属奇趣了!

这是一个线上的测试链接,感兴趣的小伙伴可以试试:https://hyperion-jhxs5uvsja-de.a.run.app/(需要科学上网)

发表评论

邮箱地址不会被公开。 必填项已用*标注