虚拟背景
在浏览器中为实时视频流添加虚拟背景的演示。
:point_right: 在这里在线试用!
目录
实现细节
在此演示中,您可以在3种不同的预训练分割模型之间切换:
BodyPix
BodyPix 提供的绘图工具并未针对此演示中简单的背景图像用例进行优化。因此,我没有使用 API 中的 toMask 或 drawMask 方法来获得更高的帧率。
未使用 BodyPix API 中的 drawBokehEffect 方法。相反,使用 CanvasRenderingContext2D.filter 属性配置 blur,并设置 CanvasRenderingContext2D.globalCompositeOperation 以根据分割蒙版混合不同的层。
结果在笔记本电脑上提供了有趣的帧率,但在移动设备上不太可用(详见 性能)。在两种设备上,与 Meet 分割模型相比,分割精度都不足。
注意:BodyPix 依赖于您设备的默认 TensorFlow.js 后端(通常是 webgl
)。对于此模型,至少在 MacBook Pro 上,WASM 后端似乎较慢。
MediaPipe Meet 分割
Meet 分割模型仅作为 TensorFlow Lite 模型文件提供。这个问题中讨论了几种将其转换并与 TensorFlow.js 一起使用的方法,但我决定尝试实现更接近 Google 在这篇文章中描述的原始方法。因此,该演示依赖于基于 TFLite 构建的小型 WebAssembly 工具,并支持 XNNPACK 代理和 SIMD。
注意:Meet 分割模型卡最初是在 Apache 2.0 许可下发布的(在这里和这里阅读更多),但似乎自 2021 年 1 月 21 日起切换到了 Google 服务条款。不确定这对此演示意味着什么。这里是与此演示中使用的模型文件相匹配的模型卡副本
将 TFLite 构建为 WebAssembly
您可以在此存储库的 tflite 目录中找到 TFLite 推理工具的源代码。使用 Docker 构建 TFLite 的说明在专门的部分中描述:构建 TensorFlow Lite 工具。
- Bazel WORKSPACE 配置受到 MediaPipe 存储库的启发。
- Bazel 的 Emscripten 工具链是按照 Emsdk 存储库说明设置的,并更改以匹配 XNNPACK 构建配置。
- 修补了 TensorFlow 源代码以匹配 Emscripten 工具链和 WASM CPU。
- 直接从 JavaScript 调用 C++ 函数以实现最佳性能。
- 从 JavaScript 通过指针偏移直接访问内存,以与 WASM 交换图像数据。
Canvas 2D + CPU
这个渲染管道与 BodyPix 的基本相同。它依赖于 Canvas 合成属性根据分割蒙版混合渲染层。
与 TFLite 推理工具的交互在 CPU 上执行,以将 UInt8 转换为 Float32 作为模型输入,并对模型输出应用 softmax。
WebGL 2
WebGL 2 渲染管道完全依赖于 webgl2
canvas 上下文和 GLSL 着色器:
- 调整输入大小以适应分割模型(仍然有CPU操作将RGBA UInt8Array复制到TFLite WASM内存中的RGB Float32Array)。
- 对分割模型输出进行Softmax处理,以获得每个像素作为人物的概率。
- 联合双边滤波器用于平滑分割蒙版并保留原始输入帧的边缘(基于MediaPipe仓库的实现)。
- 使用光线包裹将背景图像混合。
- 原始输入帧背景模糊。这里有很棒的文章1和2。
ML Kit 自拍分割
自拍分割模型的架构与Meet分割非常相似,它们似乎都是从同一个Keras模型生成的(更多详情请参见此问题)。它以Apache 2.0许可发布,你可以在本仓库中找到与此演示中使用的模型相匹配的模型卡副本(这是原始当前模型卡)。该模型从其官方构件中提取。
与模型卡中描述的不同,模型的输出是单通道,允许获得分割蒙版的浮点值。除此之外,模型使用与Meet分割完全相同的管道进行推理。然而,由于其更高的输入分辨率(详见性能),该模型的表现不如Meet分割,尽管它仍然提供比BodyPix更好的质量分割。
性能
以下是在智能手机**Pixel 3 (Chrome)**上使用设备摄像头时观察到的整个渲染管道(包括推理和后处理)的性能。
模型 | 输入分辨率 | 后端 | 管道 | FPS |
---|---|---|---|---|
BodyPix | 640x360 | WebGL | Canvas 2D + CPU | 11 |
ML Kit | 256x256 | WebAssembly | Canvas 2D + CPU | 9 |
ML Kit | 256x256 | WebAssembly | WebGL 2 | 9 |
ML Kit | 256x256 | WebAssembly SIMD | Canvas 2D + CPU | 17 |
ML Kit | 256x256 | WebAssembly SIMD | WebGL 2 | 19 |
Meet | 256x144 | WebAssembly | Canvas 2D + CPU | 14 |
Meet | 256x144 | WebAssembly | WebGL 2 | 16 |
Meet | 256x144 | WebAssembly SIMD | Canvas 2D + CPU | 26 |
Meet | 256x144 | WebAssembly SIMD | WebGL 2 | 31 |
Meet | 160x96 | WebAssembly | Canvas 2D + CPU | 29 |
Meet | 160x96 | WebAssembly | WebGL 2 | 35 |
Meet | 160x96 | WebAssembly SIMD | Canvas 2D + CPU | 48 |
Meet | 160x96 | WebAssembly SIMD | WebGL 2 | 60 |
可能的改进
- 依赖alpha通道以节省从分割蒙版获取纹理的次数。
- 在渲染循环外模糊背景图像,并将其用于光线包裹,而不是原始背景图像。这应该为大光线包裹蒙版产生更好的渲染结果。
- 优化联合双边滤波器着色器,以防止不必要的变量、计算和昂贵的函数,如
exp
。 - 尝试联合双边滤波器的可分离近似。
- 在较低的源分辨率上计算所有内容(在管道开始时缩小)。
- 构建支持多线程的TFLite和XNNPACK。一些配置示例在TensorFlow.js WASM后端中。
- 检测WASM功能以自动加载正确的TFLite WASM运行时。可以从TensorFlow.js WASM后端获得灵感,该后端基于GoogleChromeLabs/wasm-feature-detect。
- 实验DeepLabv3+,也许直接重新训练
MobileNetv3-small
模型。
相关工作
你可以在BodyPix仓库中了解更多关于预训练TensorFlow.js模型的信息。
这里是Google Meet中背景功能的技术概述,它依赖于:
- MediaPipe
- WebAssembly
- WebAssembly SIMD
- WebGL
- XNNPACK
- TFLite
- Google的自定义分割ML模型
- Google通过OpenGL着色器的自定义渲染效果
本地运行
在项目目录中,你可以运行:
yarn start
以开发模式运行应用。
在浏览器中打开http://localhost:3000查看。
如果你进行编辑,页面将重新加载。
你还将在控制台中看到任何lint错误。
yarn test
以交互式监视模式启动测试运行程序。
有关更多信息,请参阅运行测试部分。
yarn build
将应用程序构建到build
文件夹中用于生产。
它正确地打包了生产模式下的React,并优化了构建以获得最佳性能。
构建经过压缩,文件名包含哈希值。
您的应用程序已准备好部署!
有关更多信息,请参阅部署部分。
构建TensorFlow Lite工具
要在本地构建TensorFlow Lite推理工具,需要Docker。
yarn build:tflite
构建可以推理Meet和ML Kit分割模型的WASM函数。TFLite工具同时构建了带有和不带有SIMD支持的版本。