130 行代码模仿火爆抖音的“蚂蚁呀嘿”特效,你学会了吗?

【CSDN 编者按】最近很火的AI换脸来啦,本文具体操作步骤已献上,快来get一下吧。

作者 | 峰华

出品 | CSDN(ID:CSDNnews)

过去一年,线上视频会议软件异军突起,成为了在家办公的主要沟通渠道。而最近抖音中能够让照片张嘴唱歌的“蚂蚁呀嘿”特效也突然火了起来,那我就想了想能不能在视频会议的时候换张脸活跃下气氛?

在 GitHub 上一番搜寻之后发现还真有办法,有一个开源的 Python 人工智能换脸的库,那正好趁着这个机会研究一下前端 WebRTC 实现视频通话功能,外加换脸操作。

先看一下效果吧:

因为有涉及到一点点的后台,所以项目分成了两部分,一个是用于存放前端代码的 frontend 项目,另一部分是存放后端代码的 backend 项目:

项目根目录   |-- backend  |-- frontend
另外这个视频需要电脑上有摄像头,没有的话可以想办法把手机当作电脑的摄像头。
注意:本教程中的代码仅供展示 AI 换脸技术的应用,不可以用于获取其他人隐私或其他任何非法目的。

编写页面

因为是前端实现,首先肯定是编写页面。这个页面比较简单,就是一个视频组件、显示用户 ID 的文本、呼叫对方视频的输入框和按钮,视频组件默认显示自己的视频,当视频接通之后就会显示对方的视频,而自己的视频会缩小到右上角。

HTML

在 frontend 目录下新建 index.html、style.css 和 index.js 文件。首先看一下 HTML 结构,index.html 中主要的代码如下:

<!-- frontend/index.html --><head>  <!-- 其他代码 -->  <link rel="stylesheet" href="style.css" /></head><body>  <main>    <div id="container">      <div class="videos">        <video id="myVideo" class="videoSize" autoplay></video>        <video id="peerVideo" class="videoSize" autoplay></video>      </div>      <p id="idText"></p>      <div class="call">        <input type="text" id="peerIdInput" placeholder="请输入对方 id" />        <button id="joinBtn">视频通话</button>      </div>    </div>  </main>  <script src="index.js"></script></body>

每个标签的作用是:

  • <main /> 用于设置页面背景,把所有组件居中对齐。

  • <div class="videos"> 里边分别放了显示自己视频 #myVideo  和对方视频 #peerVideo<video /> 组件,并设置为自动播放,以便于在加载摄像头后立刻开始播放画面。

  • <p id="idText"> 在页面打开时显示自己的用户 ID,相当于是电话号码。

  • <div class="call"> 里是输入对方 ID 的文本框 #peerIdInput 和呼叫按钮 #joinBtn

  • 最后在 <head /> 中引入样式文件 style.css,在 <body /> 结束前引入index.js。我们将主要在 index.js 中编写代码。

CSS

CSS 的代码都比较简单,基本就是设置一下样式,这里介绍一下重要的部分,剩余的可以在源代码中查看。因为自己的视频要在视频接通时移动到右上角,那么就需要把 <div class="videos">  容器设置为相对定位,把我的视频和对方的视频设置成一样的宽高,然后先隐藏对方视频,当视频接通时,利用 JavaScript 加上接通后,我的视频的样式,把我的视频设置为绝对定位,宽高调小,放到右上角:

/* frontend/style.css */videos {  position: relative;}
.videoSize {  width: 500px;  height: 600px;  object-fit: cover;  /* 让视频按比例占满整个空间 */}
.rightTop {  /* 以下是通话中的样式 */  position: absolute;  width: 150px;  height: 180px;  right: 0;  top: 0;}
#peerVideo {  display: none;}

其他组件基本只是设置了下 Grid 布局、宽高、大小、阴影、背景、字体,没有什么特殊的,可以直接查看源代码。样式中所用到的图标在 frontend/icons 目录下。

访问摄像头

接下来我们先熟悉一下访问摄像头的代码。在 JavaScript 中访问用户的摄像头主要使用navigator.mediaDevices.getUserMedia() 方法, 它接收一个对象作为参数,用于指定要获取的设备,例如视频或音频,然后返回一个 Promise,在 Promise 完成之后它会传递给我们一个 Stream 流,我们把它放到 <video /> 标签的 srcObject 属性中就可以了,是不是很简单?代码如下:

// frontend/index.jsconst myVideo = document.getElementById("myVideo");
navigator.mediaDevices.getUserMedia({video: true, audio: true}).then((stream) => {  myVideo.srcObject = stream;});

在这段代码中:

  • 获取了 #myVideo 这个 <video /> 组件。

  • 使用 navigator.mediaDevices.getUserMedia() 并给它传递了一个对象,对象的 video 和 audio 属性都设置为了 true,表示要访问摄像头和音频设备。

这时,使用 VS Code 的 Live Server 插件运行项目(没有的话安装一下,很简单),在 index.html 文件里右击,选择 Open with Live Server,打开之后,浏览器可能会提示此网站需要访问摄像头和音频设备,点击允许,就能看到自己的视频了。

编写后台

要实现视频通话,需要使用 WebRTC 技术,这个技术牵扯的概念和 API 过于庞大和复杂,不过有开源的库来帮我们简化了 WebRTC 的操作,这里使用一个叫做 Peer.js(https://peerjs.com/)的库,它封装了 WebRTC 杂乱的 API,提供了完整的、可配置的、易于使用的 API。

我们将会通过把 Peer 附加到 Express.js 服务器上,来生成用户 ID 并管理 WebRTC 连接。首先在 backend 目录下运行:

npm init -y# 或yarn init -y
接着初始化一个 node.js 项目,使用 npm 或 yarn 安装 peer 和 express 依赖,因为想在改动代码时自动重启服务,我们也可以再安装一个 nodemon 依赖:
yarn add peer express nodemon# 或npm install --save peer express nodemon
安装完成之后新建一个 server.js 文件,整个后台服务我们就只需要这一个文件,都是一些简单的初始化代码,它里边的内容是:
const express = require("express");const { ExpressPeerServer } = require("peer");
const app = express();
const server = app.listen(3000);
const peerServer = ExpressPeerServer(server, {  debug: true,  path: "/",});
app.use("/video", peerServer);
这些代码的含义是:
  • 导入express库,并从peer库中导入与express进行结合的 ExpressPeerServer。

  • 创建 express 实例 app ,并监听 3000 端口。

  • 把 ExpressPeerServer 挂载到 express 中,设置 debug 开发模式为 true,这样有更好的错误提示。路径为根目录。

  • ExpressPeerServer 挂载之后会返回一个 express 的控制器。

  • 把返回的控制器挂载到 /video 路径下,这样 /video 路径就是主要的、peer.js 提供的 WebRTC 通信路径。

然后修改一下 package.json 文件,添加一个 script 配置项,里边定义 start 命令值为 nodemon server.js

 "scripts": {    "start": "nodemon server.js"  },
这样使用 nodemon 运行 server.js 文件后,如果 server.js 中的内容发生变化,它会自动帮助我们重启服务器。

我们现在来运行一下 yarn start 或者 npm start ,看到命令行提示 [nodemon] starting node server.js就算启动成功了,我们访问一下 http://localhost:3000/video  ,看到下方输出结果就说明 peer 也加载成功了:

{"name":"PeerJS Server","description":"A server side element to broker connections between PeerJS clients.","website":"https://peerjs.com/"}

后端代码到这里就编写完成了。下一步就是在前端页面中调用 Peer 相关的 api,并建立视频通话。

生成用户 ID

在前端中调用后端 Peer 服务可以使用 Peer.js 官方的前端库,可以直接使用 cdn 形式:

<script src="https://unpkg.com/[email protected]/dist/peerjs.min.js"></script>

也可以打开上边 src 中的网址,把文件保存到本地,或者在 GitHub 上下载:

https://github.com/peers/peerjs/blob/master/dist/peerjs.min.js

下载完成之后把它放到 frontend/peer 目录下,然后在 index.html 中,在引入 index.js 的上方,引入 peerjs:

<script src="peer/peerjs.min.js"></script>
<script src="index.js"></script>

接下来打开 index.js 文件,建立与后台 peer 服务的连接:

const peer = new Peer({
  host: "localhost",
  port: "3000",
  path: "/video",
});

这里直接使用 peer.js 前端库导出的构造函数 Peer(),它接收一个对象作为参数,这里就分别把后台服务的 host、port 和 path 传递进去就可以了,它会返回 peer 实例,后续有关视频通话的操作就主要使用它来实现。

当成功的连接到后台服务之后,我们首先给自己生成一个唯一的用户 ID,就等同于是一个电话号码,那么这里我们可以监听 peer 的 open 事件,当连接打开后,会把生成的用户 ID 返回到事件处理回调函数中,然后我们获取 html 中的 #idText 这个 p 元素来显示自己的 ID:

const idText = document.getElementById("idText");


peer.on("open", (id) => {
  idText.textContent = "我的 id 是:" + id;
});

这时在 Live Server 中打开 index.html,就可以看到显示出了 ID,类似于:

我的 id 是:2573c3ae-ba79-404a-b807-2128856ef3c9

多打开几个页面,可以看到每个人的 ID 都不同。

呼叫视频通话

在有了用户 ID 之后,就可以呼叫对方了。这里的逻辑是,用户在输入框输入对方 ID 之后,点击视频通话按钮进行呼叫。那么我们应该先获取视频通话按钮元素,然后监听它的点击事件,在里边发起呼叫:

const joinBtn = document.getElementById("joinBtn");
// 发起呼叫
joinBtn.addEventListener("click", () => {
  const peerId = peerIdInput.value;
  console.log("正在连接:" + peerId);


  navigator.mediaDevices.getUserMedia({video: true, audio: true}).then((stream) => {
    const call = peer.call(peerId, stream);
    call.on("stream", showVideo);
  });
});

在点击按钮的时候,事件处理函数作了如下操作:

  • 获取用户输入的对方的 ID。

  • 获取当前用户的视频流,然后调用peer.call()呼叫对方, peer.call() 需要对方的 ID 和自己的视频流作为参数,然后返回与呼叫有关的实例,保存到 call 中。

  • 这时当前用户就开始等待对方应答了,为了简单起见,这里没有做等待的样式。

  • 下一步监听 call 的 stream 事件,这个事件会在对方应答后触发,它会返回对方的视频流作为事件处理函数的参数,然后我们使用 showVideo() 函数处理对方的视频流。

showVideo() 函数的代码如下:

const peerVideo = document.getElementById("peerVideo");


function showVideo(stream) {
  myVideo.classList.add("rightTop");
  peerVideo.srcObject = stream;
  peerVideo.style.display = "block";
}

这个函数就是简单的把自己的视频移动到右上角,通过之前定义的 .rightTop class 样式,然后把对方的视频流放到 #peerVideo 视频组件中,之后把它显示出来(之前设置的是 display: none 隐藏)。现在因为一直是等待对方接听,所以需要有一个应答的处理。

应答视频通话

应答的处理是监听 peer 的 call 事件,然后通过事件参数中与呼叫有关的实例来应答通话:

// 应答呼叫
peer.on("call", (call) => {
  navigator.mediaDevices.getUserMedia({video: true, audio: true}).then((stream) => {
    call.answer(stream);
    call.on("stream", showVideo);
  });
});

这一步的代码虽然在同一个文件中,但是应该想象为收到视频通话呼叫的对方,代码作了下边的操作:

  • 获取自己的视频流。

  • 调用 answer() 函数应答视频呼叫,并把自己的视频流传回给呼叫者。这里是当有呼叫时直接进行应答,为了简单起见,没有编写点击应答按钮相关的样式和事件。

  • 监听stream事件,这一步和之前的一样,应答后这个事件就会触发,然后同样使用 showVideo() 函数加载视频。

好了,现在打开两个页面试试,在其中一个页面输入另一个页面生成的 ID,然后点击视频通话,就可以看到双方视频显示出来了。如果用的是同一个摄像头,那么显示的画面都是一样的。

实现换脸

实现换脸主要是用到了 Avatarify 这个 AI 换脸库,它是使用 Python 编写的,利用了 First-Order Motion Model算法来实现换脸。我们这里只需要按照步骤进行安装就可以了,此外还需要安装虚拟摄像头软件,用于把 Avatarify 换脸后的数据作为摄像头视频,然后在前端页面中访问这个虚拟的摄像头。

Avatarify 由于是对摄像头的视频进行实时计算,所以对显卡的要求非常高,且只支持启用了 CUDA 的 Nvidia 显卡来进行 GPU 加速,官方的统计数据是这样的:

  • GeForce GTX 1080 Ti: 33 帧/秒

  • GeForce GTX 1070: 15 帧/秒

  • GeForce GTX 950: 9 帧/秒

如果配置达不到,可以使用腾讯云或阿里云的 GPU 实例,把显卡有关的计算交给远程服务器去进行,本地只需要建立视频流即可。本文将主要使用这种方法。

如果配置达到了要求,也可以在本地安装运行,不过我没有试过,后边简单的贴一下官方安装指导(Windows 下),你可以自己尝试一下。

要注意的是,如果是在本地运行算法,可以在 Windows 和 Linux 操作系统中进行,或者也可以使用 Docker 进行部署,不过只支持 Linux 操作系统下的 Docker。

购买服务器

这里以腾讯云 GPU 实例为例,介绍一下服务器的配置,关于计费我们会使用按量计费,完成这篇教程所用的总体费用可能在 30 元左右,用完之后一定要记得关机或者销毁来停止计费。如果是关机,记得先把带宽调整为 0,停止带宽计费,然后关机时选择关机不收费选项。

然后在选择机型中选择如下配置:

  • 计费模式:按量计费。

  • 实例:选择 GPU 型,在机型列表中选择 GPU 计算型 GN7,这个是最便宜的,7.16 元/小时。

  • 镜像:选择 Ubuntu 64位 18.04,不要选过高的版本。显卡驱动可能支持不完善。

  • 勾选上后台自动安装 GPU 驱动,CUDA 版本选择 10.0.130,cuDNN 版本选择 7.4.2。

  • 带宽实测需要 20M 起步,大概 1 元/小时,不过在安装 Avatarify 的时候带宽可以小一点,后边真正开启视频的时候再把它改大。

  • 注意这里系统盘费用是 0.03 元/小时,这个在关机后仍然会收取。

在下一步设置主机中:

  • 新建安全组。

  • 登录方式这里使用密码,可以选择自行设置,也可以自动生成。

再下一步确认成功后完成购买,稍后就可以在控制台实例列表中看到刚购买的实例了,新购买的机器可能需要等5分钟才能配置完成。如果要修改带宽,可以在列表中找到对应的实例,在最右侧操作栏里选择更多->资源调整->调整带宽,进行调整。

因为 Avatarify 需要使用 5557 和 5558 端口,我们需要在安全组中放行这两个端口。点击实例名称超链接,进入实例详情页面,在上方选项卡中选择 安全组 ,在右侧规则预览中的入站规则选项卡里,点击编辑规则,在新页面里的入站规则里,点击添加规则,在对话框里填写:

  • 类型:自定义。

  • 来源:all。

  • 协议端口:TCP:5557,5558

  • 策略:允许。

点击完成即可。到这里实例配置就完成了,留意一下实例的公网 IP 地址,稍后使用 SSH 登录时需要用到它。

部署 Avatarify

我们使用 Docker 的方式来部署 Avatarify,先登录到我们的 GPU 实例中,可以直接在腾讯云控制台登录,也可以使用 ssh 命令或 putty 工具。这里以 ssh 为例,输入如下命令:

ssh ubuntu@你的实例ip

然后根据提示输入密码,第一次登录可能有一大段英文提示(是否信任设备),直接输入 yes 回车即可。

安装 Docker

登录进去之后先安装 Docker,可以直接使用简易的安装脚本:

curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh

如果无法访问这个脚本,我们还可以使用普通方式安装,按照以下步骤复制粘贴命令:

# 第一步
sudo apt-get update


# 第二步
sudo apt-get install \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg  


# 第三步
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg


# 第四步
echo \
  "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

这些步骤都是在配置 Docker 的安装仓库源和密钥,接下来运行下面两条命令来安装 Docker:

sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io

安装完成之后,docker命令需要管理员权限才能运行,每次都需要输入 sudo,如果要省略sudo ,可以把当前用户(腾讯云默认为 ubuntu)添加到 docker 用户组中:

sudo usermod -aG docker ubuntu

之后退出 ssh 并重新登录来让配置生效,我们可以运行下面的命令检查 Docker 是否安装成功:

docker run hello-world

有打印出 hello world 字样和一大段英文就说明成功了。

安装 Nvidia Docker tookit

要让 docker 使用 GPU,需要安装 Nvidia Docker tookit,这一步也很简单,首先设置 Nvidia 的仓库源:

distribution=$(. /etc/os-release;echo $ID$VERSION_ID) \
   && curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add - \
   && curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list

然后安装 tookit 并重启 Docker:

sudo apt-get update
sudo apt-get install -y nvidia-docker2
sudo systemctl restart docker

运行一个示例 container 检查是否安装成功:

sudo docker run --rm --gpus all nvidia/cuda:11.0-base nvidia-smi

如果打印出类似的如下信息就算成功了:

Fri Mar  5 08:47:39 2021
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 418.126.02   Driver Version: 418.126.02   CUDA Version: 11.0     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  Tesla T4            Off  | 00000000:00:08.0 Off |                    0 |
| N/A   26C    P8     9W /  70W |      0MiB / 15079MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+


+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID   Type   Process name                             Usage      |
|=============================================================================|
|  No running processes found                                                 |
+-----------------------------------------------------------------------------+

构建 Avatarify Docker 镜像

选择一个文件夹,使用 git 克隆 Avatarify 仓库:

git clone https://github.com/alievk/avatarify.git

进入到克隆下来的 avatarify 仓库中,使用 docker 构建镜像:

cd avatarify
docker build -t avatarify .

构建需要的时间比较长,耐心等待完成之后,启动服务:

bash run.sh --is-worker --docker

看到有 5557 和 5558 端口就说明启动成功了。到现在,Avatarify 的服务端配置完成了,之后就是使用客户端调用服务,把计算部分交给我们的 GPU 实例。这时如果担心计费,可以先把实例关机,在本地安装好客户端后再开机。

接下来的步骤以 MacOS 为例,Windows 版可以直接跳到后边的 Windows 安装方法 小节。

安装 Avatarify 客户端

在本地电脑上,首先安装 Miniconda Python 3.8,可以从这里下载:

https://docs.conda.io/en/latest/miniconda.html#macosx-installers

或者使用 Homebrew:

brew install --cask miniconda

克隆 avatarify 仓库并运行安装脚本:

git clone https://github.com/alievk/avatarify.git
cd avatarify
bash scripts/install_mac.sh

下载 CamTwist 虚拟摄像头软件(类似 OBS,但是 OBS 的虚拟摄像头在 Mac 中访问不到)并安装:

http://camtwiststudio.com/download

启动 Avatarify 客户端

确保远程 GPU 实例已启动,且运行了 avatarify docker 镜像监听 5557 和 5558 端口,然后在本地克隆的 avatarify 仓库中,运行 mac 客户端:

./run_mac.sh --is-client --in-addr tcp://server_address:5557 --out-addr tcp://server_address:5558

记得把两个server_address改成 GPU 实例的公网 IP。服务端可能需要下载一些必要的文件,所以连接会慢一些,稍等启动成功后 Avatarify 会自动打开摄像头窗口。

我们可以根据提示调整好脸部位置,这里我们最好把脸放到红色矩形框中,光线要充足,不能太黑,可以使用 W/D 键缩放画面,调整好之后按 X 键就可以呼出换脸之后的预览视频窗口,它就是作为虚拟摄像头的视频来源。

Avatarify 内置了 9 张示例的人脸照片,可以按 1-9 键进行切换,也可以自定义人脸照片,放到 Avatarify 中的avatars文件夹下。

Avatarify 成功显示之后,打开 CamTwist 虚拟摄像头,在左侧选择 Desktop+,然后点击底部的 select,然后在右侧的 settings 下,勾上 Confine to Application Window,然后勾上下方的 Select from existing windows ,在下拉框中选择 python (avatarify) ,如果找不到可以退出 CamTwist 重新打开,或者多点击下拉框几次试试。现在虚拟摄像头就准备好了。

Windows 安装方法

在 Windows 下的安装方法与 MacOS 类似,而且如果显卡配置够高,可以省略购买远程 GPU 服务器步骤。

  1. 首先安装 Minicoda Python 3.8,可以从这里下载:

https://docs.conda.io/en/latest/miniconda.html#windows-installers

  1. 安装完成之后打开 Anaconda 命令提示符,克隆 avatarify 仓库,并运行 windows 操作系统下的安装脚本:

git clone https://github.com/alievk/avatarify.git
cd avatarify
scripts\install_windows.bat
  1. 如果要在本地执行换脸算法,那么需要下载 network weights(228 MB):

https://openavatarify.s3.amazonaws.com/weights/vox-adv-cpk.pth.tar

https://yadi.sk/d/M0FWpz2ExBfgAA

https://drive.google.com/file/d/1coUCdyRXDbpWnEkA99NLNY60mb9dQ_n3/view?usp=sharing

  1. 下载完成后放到 avatarify 的根目录下,无需解压。

  2. 运行 avatarify 客户端,如果是在本地运行,可以使用:

./scripts/run_windows.bat
  1. Windows 系统下也可以使用远程 GPU 实例,使用下面的方式启动客户端:

./scripts/run_windows.bat --is-client --in-addr tcp://server_address:5557 --out-addr tcp://server_address:5558
  1. 两个server_address需要替换成远程 GPU 实例的公网 IP。

  2. 启动成功之后和 Mac 的操作一样,使用 W/D 缩放画面,完成之后按 X 键调出 avatarify 预览窗口。

Windows 下的虚拟摄像头可以使用 OBS,最新版的 OBS 26.1 及以上已经内置了虚拟摄像头插件了,无需再单独安装。

  1. 下载并安装 OBS:

https://obsproject.com/

  1. 安装完成之后打开 OBS,在左下角的 Source(源)面板中添加 Windows Capture,把视频输入源设置为某个应用程序窗口,然后选择 [python.exe]: avatarify 程序,点击 OK,可以调整以下大小。

  2. 再在 Tools(工具)菜单中选择 VirtualCam(虚拟摄像头),选择 AutoStart(自动开启),设置 Buffered Frames(缓冲)为 0,然点击开始。(如果 Tools 菜单没有 VirtualCam,看看界面右下角的 start recording 附近有没有 start virtual cam)。

现在虚拟摄像头就准备好了。

实现换脸

接下来就是在我们的视频通话前端项目中,使用 CamTwist 或 OBS 提供的虚拟摄像头了。我们需要明确知道它们的设备 ID 才能指定具体使用哪个摄像头。

首先使用 Live Server 打开前端项目的 index.html 文件,在谷歌开发者工具的 console 中,使用下面这段代码打印出视频设备信息:

navigator.mediaDevices.enumerateDevices()
.then(function(devices) {
  devices.forEach(function(device) {
    if(device.kind === "videoinput") {
      console.log(device);
    }
  });
})

这段代码就是访问所有媒体设备,然后获取其中的视频设备并打印出来,从打印结果里找到 label 包含 CamTwist 或者 OBS(视操作系统而定)的那一项,记录 deviceId 属性。

在 index.js 文件中,保存 deviceId 值到一个常量中:

const cameraId =
  "982947417cf490bae44ffb6a837bddcb813704ee491dd85d9149c45389f5521b";

在使用navigator.mediaDevices.getUserMedia()获取摄像头时,除了可以把 video 设置为 true 之外,还可以把他的值设置为一个对象,用来指定更多的信息,我们把它单独定义出来,在里边使用 cameraId 指定访问哪个摄像头:

const mediaConstrains = {
  video: {
    deviceId: {
      exact: cameraId,
    },
  },
  audio: true,
};

exact 是精确的、只使用指定 ID 的摄像头,不会使用其他备选的。

然后在获取自己摄像头设备的部分,替换成上边这个对象。或者为了方便测试,也可以把所有的都替换掉:

navigator.mediaDevices.getUserMedia(mediaConstrains).then(/* ... */)

好了,现在再试试视频通话,是不是成功的换脸了呢?

这里要注意的是,可能是因为 CamTwist 软件和真正的摄像头有冲突,页面会不时的重新刷新,这个暂时还没有比较好的解决方案,如果你有精力的话可以研究一下。

附上本文的源代码:

https://github.com/zxuqian/code-examples/tree/master/webrtc/video-call-change-face

总结

这篇教程所用到的技术都很简单,只是配置比较复杂,本教程提供了换脸的基本步骤,剩下的可以根据需要继续进行完善。示例中实现的的是一对一的视频通话,不过在这个基础上也完全可以实现多方视频会议,只需要调整一下视频显示的样式,然后在有新人加进来时,创建相应的<video />标签,并追加到现有的视频列表中即可。现在我们来回顾一下过程:

  • 编写前端 HTML/CSS 页面结构和样式,并尝试加载摄像头。

  • 编写简单的后台应用,利用 epxress 和 peer 建立基于 WebRTC 的视频通话基础。

  • 前端利用 peer.js 前端库调用后台生成用户 ID,并呼叫、应答视频通话。

  • 配置 Avatarify 换脸服务器程序,利用云 GPU 服务把显卡计算相关部分转移到 GPU 实例中。

  • 安装 Avatarify 客户端程序和虚拟摄像头应用,把换脸后的数据用虚拟摄像头展现出来。

  • 前端获取虚拟摄像头 ID,在视频通话的时候使用此摄像头。

如果有帮助请点赞并分享,有问题可以评论留言,感谢阅读!

作者:峰华,简介:前端工程师,以直观、专业的方式分享编程知识。Bilibili UP@峰华前端工程师



☞微信Mac版更新:在电脑上刷朋友圈;领英暂停中国境内新用户注册;Git 恶意仓库可以在克隆时执行远程代码 | 极客头条☞被“钱”困住的开源开发者们!
☞欧洲云计算巨头机房起火,数据中心成灰烬!Rust 游戏玩家:我白玩了
☞在内存只有24KB的电脑上写操作系统,是怎样的体验?

猜你喜欢

转载自blog.csdn.net/csdnnews/article/details/114715011
130