概述
注意:这是一个跟踪库,不是一个独立的头像操控程序。我也在开发 VSeeFace,它允许使用OpenSeeFace跟踪来动画化 VRM 和 VSFAvatar 3D模型。VTube Studio 使用OpenSeeFace进行基于网络摄像头的跟踪以动画化Live2D模型。一个用于Godot引擎的渲染器可以在这里找到。
该项目实现了一个基于MobileNetV3的面部标志检测模型。
由于Pytorch 1.3在Windows上的CPU推理速度非常慢,模型被转换为ONNX格式。使用onnxruntime可以在30 - 60 fps的速率下对单个面部进行跟踪。有四个模型,具有不同的速度与跟踪质量的权衡。
如果有人好奇,名称是一个对“开放的海洋”和“看到面孔”的有趣双关,没有更深层的含义。
一个最新的样本视频可以在这里找到,展示了默认跟踪模型在不同噪声和光线条件下的性能。
跟踪质量
由于OpenSeeFace使用的标志与其他方法使用的标志略有不同(它们与iBUG 68接近,但在嘴角少了两个点,并且面部轮廓是准3D的而不是跟随可见轮廓的面部轮廓),很难在数值上将其准确性与科学文献中常见的其他方法进行比较。跟踪性能也更为优化,适用于创建对动画化头像有用的标志,而非精确地适合面部图像。例如,只要眼睛标志显示眼睛是打开还是关闭的,即使其位置有些偏离,也仍然可以用于此目的。
从一般观察来看,OpenSeeFace在不利条件下(光线不足,噪声高,分辨率低)表现良好,并且在非常广泛的头部姿势范围内保持面部标志位置的相对高稳定性。与MediaPipe相比,OpenSeeFace标志在具有挑战性的条件下更稳定,并且更准确地表示更广泛的嘴部姿势。然而,眼部区域的跟踪可能不那么准确。
我运行了一个来自视频演示 3D Face Reconstruction with Dense Landmarks 的样本剪辑来比较OpenSeeFace与MediaPipe及其方法的表现。你可以在这里观看结果。
使用方法
一个基于VRM的头像动画的Unity样本项目可以在这里找到。
面部跟踪是由 facetracker.py
Python 3.7 脚本完成的。这是一个命令行程序,因此你应该从cmd手动启动它或编写一个批处理文件来启动它。如果你下载了一个发布版本并且在Windows上,你可以运行 Binary
文件夹内的 facetracker.exe
而无需安装Python。你也可以使用 Binary
文件夹内的 run.bat
来进行跟踪器的基本演示。
脚本将对网络摄像头输入或视频文件执行跟踪并通过UDP发送跟踪数据。此设计还允许在使用跟踪信息的计算机与进行跟踪的计算机分开进行跟踪。这有助于提高性能并避免意外泄露摄像机画面。
所提供的 OpenSee
Unity组件可以接收这些UDP数据包并通过名为 trackingData
的公共字段提供接收到的信息。OpenSeeShowPoints
组件可以可视化检测到的面部标志点。它也作为一个示例。请查看它以了解如何正确使用 OpenSee
组件。Examples
文件夹中包含进一步的示例。UDP数据包在一个单独的线程中接收,因此任何使用 OpenSee
组件的 trackingData
字段的组件应首先复制该字段并访问该副本,因为否则在处理中信息可能被覆盖。此设计也意味着即使 OpenSee
组件被禁用,该字段仍会更新。
使用 --help
运行python脚本以了解你可以设置的选项。
python facetracker.py --help
可以通过在Unity中创建一个新场景,添加一个空游戏对象并添加 OpenSee
和 OpenSeeShowPoints
组件,实现简单的演示。当场景播放时,在视频文件上运行面部跟踪器:
python facetracker.py --visualize 3 --pnp-points 1 --max-threads 4 -c video.mp4
注意:如果使用poetry安装了依赖项,命令必须从 poetry shell
执行,或者必须在命令前加上 poetry run
。
通过这种方式,跟踪脚本将输出其自己的跟踪可视化,同时也演示向Unity传输跟踪数据。
包含的 OpenSeeLauncher
组件允许从Unity启动面部跟踪器程序。它设计为与二进制发布包中分发的pyinstaller创建的可执行文件一起工作。它提供了三个公共API功能:
public string[] ListCameras()
返回可用摄像头的名称。数组中摄像头的索引对应其在cameraIndex
字段中的ID。将cameraIndex
设置为-1
将禁用网络摄像头捕获。public bool StartTracker()
将启动跟踪器。如果跟踪器已经在运行,它将关闭正在运行的实例,并使用当前设置启动一个新的实例。public void StopTracker()
将停止跟踪器。当应用程序终止或OpenSeeLauncher
对象被销毁时,跟踪器会自动停止。
OpenSeeLauncher
组件使用WinAPI作业对象确保如果应用程序崩溃或在未首先终止跟踪器进程的情况下关闭,跟踪器子进程将终止。
额外的自定义命令行参数应一个一个地添加到 commandlineArguments
数组的元素中。例如 -v 1
应作为两个元素添加,一个包含 -v
,一个包含 1
,而不是一个包含两部分的元素。
包含的 OpenSeeIKTarget
组件可以与FinalIK或其他IK解决方案一起使用以动画化头部运动。
表情检测
OpenSeeExpression
组件可以添加到与 OpenSeeFace
组件相同的组件中以检测特定的面部表情。它必须根据用户进行校准。可以通过Unity编辑器中的复选框或其源代码中的等效公共方法进行控制。
要校准此系统,你必须为每个表情收集示例数据。如果捕获过程进行得太快,你可以使用 recordingSkip
选项来减慢速度。
一般过程如下:
- 输入要校准的表情名称。
- 做出表情并保持,然后勾选记录框。
- 保持表情,并四处移动你的头部并将其转向各种方向。
- 片刻后,如果表情应与说话兼容,开始在此过程中说话。
- 这样做一会儿后,取消记录框并开始捕获另一个表情。
- 勾选训练框,查看你收集数据的表情是否被准确检测到。
- 你还应该在组件的下部看到一些统计数据。
- 如果有任何表情检测有问题,请继续向其添加数据。
要删除表情的捕获数据,请输入其名称并勾选“清除”框。
要保存训练的模型和捕获的训练数据,请在“文件名”字段中输入包含完整路径的文件名并勾选“保存”框。要加载,请输入文件名并勾选“加载”框。
提示
- 一个合理的表情数量是六个,包括中性表情。
- 在开始捕捉表情之前,做一些面部表情并抖动你的眉毛,以预热跟踪器的功能检测部分。
- 一旦你有一个工作良好的检测模型,在使用它时花点时间检查所有表情是否按预期工作,如果没有,添加一些数据。
一般注意事项
- 即使在面部部分被遮挡、佩戴眼镜或光线不良的情况下,跟踪似乎也相当稳健。
- 使用
--model 3
选择最高质量的模型,使用--model 0
选择最快但跟踪质量最低的模型。 - 较低的跟踪质量主要意味着更僵硬的跟踪,使得检测眨眼和眉毛运动更加困难。
- 根据帧率,面部跟踪可能会轻易占用整个CPU核心。在30fps下跟踪单个面部,它应该仍然使用不到一个核心的100%。如果跟踪使用了太多的CPU,尝试降低帧率。20的帧率可能是合适的,超过30的帧率通常不必要。
- 设置的跟踪面部数量高于实际视野中的面部数量时,面部检测模型将每
--scan-every
帧运行一次。这可能会减慢速度,因此尝试将--faces
设置不高于实际跟踪的面部数量。
模型
包括四个预训练的面部标志模型。使用 --model
开关,可以选择它们进行跟踪。给定的fps值是基于单个CPU核心在单面视频上运行该模型的情况。降低帧率将相应地减少CPU使用量。
- 模型 -1:此模型旨在运行在性能很低的设备上,所以它非常非常快且准确度极低。(213fps,无凝视跟踪)
- 模型 0:这是一个非常快但准确度较低的模型。(68fps)
- 模型 1:这是一个稍慢但准确度更高的模型。(59fps)
- 模型 2:这是一个更慢但准确度较高的模型。(50fps)
- 模型 3(默认):这是最慢但最准确的模型。(44fps)
fps测量结果来自在我CPU的一个核心上运行。
用于 model.py
的Pytorch权重可以在这里找到。 一些未优化的ONNX模型可以在这里找到。
结果
标志
更多样本:Results3.png,Results4.png
面部检测
标志模型对面部的大小和方向具有相当的鲁棒性,因此自定义面部检测模型的边界框比其他方法的边界框粗糙,但对于本项目的目的,它的速度与准确度比率相当有利。
发行版本
在此代码库的发布部分中的构建包含一个 facetracker.exe
文件,它位于一个使用 pyinstaller
构建的 Binary
文件夹中,并包含所有必需的依赖项。
要运行它,至少需要将 models
文件夹放置在与 facetracker.exe
相同的文件夹中。将它放在一个公共的父文件夹中也可以工作。
在分发它时,您还应分发 Licenses
文件夹,以确保符合某些第三方库提出的要求。未使用的模型可以从重新分发的软件包中移除而没有问题。
发布版本包含一个自定义的没有遥测功能的 ONNX Runtime 构建。
依赖项(Python 3.6 - 3.9)
- ONNX Runtime
- OpenCV
- Pillow
- Numpy
可以使用 pip 安装所需的库:
pip install onnxruntime opencv-python pillow numpy
或者,也可以使用 poetry 在一个单独的虚拟环境中安装此项目的所有依赖项:
poetry install
依赖项
- onnxruntime
- OpenCV
- Pillow
- Numpy
可以使用 pip 安装所需的库:
pip install onnxruntime opencv-python pillow numpy
参考文献
训练数据集
该模型在 LS3D-W 数据集的66点版本上训练。
@inproceedings{bulat2017far,
title={How far are we from solving the 2D \& 3D Face Alignment problem? (and a dataset of 230,000 3D facial landmarks)},
author={Bulat, Adrian and Tzimiropoulos, Georgios},
booktitle={International Conference on Computer Vision},
year={2017}
}
在将 WFLW 数据集减少到 66 点并用到目前为止训练的模型预测出的点替换轮廓点和鼻尖后,进行了额外的训练。这种额外的训练是为了改善对眼睛和眉毛的拟合。
@inproceedings{wayne2018lab,
author = {Wu, Wayne and Qian, Chen and Yang, Shuo and Wang, Quan and Cai, Yici and Zhou, Qiang},
title = {Look at Boundary: A Boundary-Aware Face Alignment Algorithm},
booktitle = {CVPR},
month = June,
year = {2018}
}
为了训练注视和眨眼检测模型,使用了 MPIIGaze 数据集。另外,还使用了在训练期间生成的约 125000 个使用 UnityEyes 生成的合成眼睛。
应该注意的是,训练过程中还使用了额外的自定义数据,并且为了处理各种问题,原始数据集的参考标记进行了某些方式的修改。仅使用原始的 LS3D-W 和 WFLW 数据集可能无法重现这些模型,然而这些附加数据无法重新分发。
基于热图回归的面部检测模型是在 WIDER FACE 数据集的随机 224x224 裁剪图像上进行训练的。
@inproceedings{yang2016wider,
Author = {Yang, Shuo and Luo, Ping and Loy, Chen Change and Tang, Xiaoou},
Booktitle = {IEEE Conference on Computer Vision and Pattern Recognition (CVPR)},
Title = {WIDER FACE: A Face Detection Benchmark},
Year = {2016}
}
算法
算法的灵感来源于:
- Designing Neural Network Architectures for Different Applications: From Facial Landmark Tracking to Lane Departure Warning System by YiTa Wu, Vice President of Engineering, ULSee
- Real-time Human Pose Estimation in the Browser with TensorFlow.js
- U-Net: Convolutional Networks for Biomedical Image Segmentation by Olaf Ronneberger, Philipp Fischer, Thomas Brox
- MobileNets: Efficient Convolutional Neural Networks for Mobile Vision Applications by Andrew G. Howard, Menglong Zhu, Bo Chen, Dmitry Kalenichenko, Weijun Wang, Tobias Weyand, Marco Andreetto, Hartwig Adam
- Searching for MobileNetV3 by Andrew Howard, Mark Sandler, Grace Chu, Liang-Chieh Chen, Bo Chen, Mingxing Tan, Weijun Wang, Yukun Zhu, Ruoming Pang, Vijay Vasudevan, Quoc V. Le, Hartwig Adam
MobileNetV3 的代码取自这里。
所有训练都使用了 Adaptive Wing Loss 的一个修改版本。
- Adaptive Wing Loss for Robust Face Alignment via Heatmap Regression by Xinyao Wang, Liefeng Bo, Li Fuxin
表情检测使用了 LIBSVM。
面部检测是使用自定义的基于热图回归的面部检测模型或 RetinaFace 进行的。
@inproceedings{deng2019retinaface,
title={RetinaFace: Single-stage Dense Face Localisation in the Wild},
author={Deng, Jiankang and Guo, Jia and Yuxiang, Zhou and Jinke Yu and Irene Kotsia and Zafeiriou, Stefanos},
booktitle={arxiv},
year={2019}
}
RetinaFace 检测基于此实现。预训练模型已修改以移除不必要的标记检测,并且转换为 640x640 分辨率的 ONNX 格式。
致谢
非常感谢帮助我测试的所有人!
- @Virtual_Deat,他也激励我开始从事这个项目。
- @ENiwatori 和他的家人。
- @ArgamaWitch
- @AngelVayuu
- @DapperlyYours
- @comdost_art
- @Ponoki_Chan
许可证
代码和模型根据 BSD 2-Clause 许可分发。
您可以在 Licenses
文件夹中找到用于二进制构建的第三方库的许可证。