最近看到Google发布了Tensorflow.js关于手势姿态检测模型的新版本,该模型改进了2D精度,支持3D,并具有同时预测双手关键点的新能力。晚上下班回来,把源码下载下来跑了一下demo,被这个精度惊艳到了。瞬间萌生了了一个想法,有了这个3D手势检测算法,那我是不是可以把佛山无影手的招式记录下来,然后把它教给机器人,然后让机器人给我当保镖!
先来看一下测试效果。
基于MediaPipe 和 TF.js的3D手势检测
哈哈哈,废话少说,还是来看看,今晚是怎么跑这个demo的吧。
这个TF是基于js写的,所以当然你需要安装node和yarn啦!
那么安装完这两个东西之后,我们就可以把这个tfjs-models给他下载下来:
git clone https://github.com/tensorflow/tfjs-models.git
下载下俩之后,直接运行是不行滴,需要替换掉里面的两个文件。
rm tfjs-models/hand-pose-detection/src/shared
cp -r tfjs-models/shared tfjs-models/hand-pose-detection/src
rm tfjs-models/hand-pose-detection/demos/live_video/src/shared
cp -r tfjs-models/shared tfjs-models/hand-pose-detection/demos/live_video/src
cp tfjs-models/hand-pose-detection/demos/shared/* tfjs-models/hand-pose-detection/demos/live_video/src/shared/
替换完成之后,我们就可以构建项目啦:
cd tfjs-models/hand-pose-detection/demos/live_video
rm -rf .cache dist node_modules
yarn build-dep
yarn
yarn watch
最后你会在控制台看到如下输出:
并且浏览器弹出如下提示对话框,但是请注意,该url是不行滴,还要加上模型参数才可以。
在浏览器上输入 http://localhost:1234/?model=mediapipe_hands
你就可以看到这个测试demo啦
手机端前置摄像头手势检测:
基于MediaPipe 和 TF.js的3D手势检测
当然,上面只是小试牛刀。你还可以用js、python或者在android手机中来调用上述模块。下面为官方用法。
如何使用
通过脚本标记
通过NPM
yarn add @tensorflow-models/hand-pose-detection
# Run below commands if you want to use TF.js runtime.
yarn add @tensorflow/tfjs-core @tensorflow/tfjs-converter
yarn add @tensorflow/tfjs-backend-webgl
# Run below commands if you want to use MediaPipe runtime.
yarn add @mediapipe/hands
如果是通过NPM安装的,需要先导入库:
import * as handPoseDetection from '@tensorflow-models/hand-pose-detection';
接下来创建检测器的实例:
const model = handPoseDetection.SupportedModels.MediaPipeHands;
const detectorConfig = {
runtime: 'mediapipe', // or 'tfjs'
modelType: 'full'
};
detector = await handPoseDetection.createDetector(model, detectorConfig);
选择一个适合您的应用程序需要的模型类型,有两个选项供您选择:lite和full。从lite到full,精度增加,而推理速度下降。
const video = document.getElementById('video');
const hands = await detector.estimateHands(video);
输出格式如下:手表示图像框中检测到的手预测的数组。对于每只手,该结构包含一个左右手倾向的预测(左或右)以及这个预测的置信度得分。还返回一个2D关键点数组,其中每个关键点包含x、y和名称。x, y表示手关键点在图像像素空间中的水平和垂直位置,name表示联合标签。除了2D关键点,我们还以公制尺度返回3D关键点(x, y, z值),原点以辅助关键点的形式。
[
{
score: 0.8,
Handedness: 'Right',
keypoints: [
{x: 105, y: 107, name: "wrist"},
{x: 108, y: 160, name: "pinky_finger_tip"},
...
]
keypoints3D: [
{x: 0.00388, y: -0.0205, z: 0.0217, name: "wrist"},
{x: -0.025138, y: -0.0255, z: -0.0051, name: "pinky_finger_tip"},
...
]
}
]
你可以参考我们的README了解更多关于API的细节。
TF js手部姿态检测API的更新版本提高了2D关键点预测、判断左右手(分类输出是左手还是右手)的质量,并最大限度地减少了假阳性检测的数量。关于更新模型的更多细节可以在其最近的文章中找到: On-device Real-time Hand Gesture Recognition.
在TensorFlow.j发布BlazePose GHUM 3D之后,他们还在该版本中添加了metric-scale 3D关键点预测手部姿势检测,原点由一个辅助关键点表示,形成了食指、中指、无名指和小指的第一指节。我们的三维模型是基于一个名为GHUM的统计三维人体模型,该模型是使用大量的人体形状和运动的语料库构建的。
为了获得收姿势的真实情况,其将GHUM手模型拟合到现有的2D手数据集,并恢复真实世界的三维关键点坐标。优化GHUM手模型的形状和手位变量,使重建模型与图像证据对齐。这包括2D关键点对齐、形状和姿态正则化以及人体测量关节角度限制和模型自接触惩罚。
在这个新版本中,我们大大提高了模型的质量,并在美国手语(ASL)手势数据集上对它们进行了评估。按照 COCO keypoint challenge methodology建议,我们使用均值平均精度(mAP)作为2D屏幕坐标的评价指标。
三维评价采用欧几里得三维度量空间的平均绝对误差,平均误差以厘米为单位。
Model Name | 2D, mAP, % | 3D, mean 3D error, cm |
HandPose GHUM Lite | 79.2 | 1.4 |
HandPose GHUM Full | 83.8 | 1.3 |
Previous TensorFlow.js HandPose | 66.5 | N/A |
我们在多个设备上对模型进行了基准测试。所有基准测试都是用双手进行的。
MacBook Pro 15” 2019. Intel core i9. AMD Radeon Pro Vega 20 Graphics. (FPS) |
iPhone 11 (FPS) |
Pixel 5 (FPS) |
Desktop Intel i9-10900K. Nvidia GTX 1070 GPU. (FPS) |
|
MediaPipe Runtime With WASM & GPU Accel. |
62 | 48 | 8 | 5 |
TensorFlow.js Runtime With WebGL backend |
36 | 31 | 15 | 12 |
要在你的设备上看到模型的FPS,请尝试我们的演示。你可以在演示UI中切换模型类型和运行时,看看什么最适合你的设备。
除了JavaScript手部姿势检测API,这些更新的手部模型也可以在MediaPipe Hands中作为一个现成的Android解决方案API和Python解决方案API使用,在Android Maven Repository和Python PyPI中分别有预构建的包。
例如,对于Android开发者来说,Maven包可以很容易地集成到Android Studio项目中,只需在项目的Gradle依赖项中添加以下内容:
dependencies {
implementation 'com.google.mediapipe:solution-core:latest.release'
implementation 'com.google.mediapipe:hands:latest.release'
}
MediaPipe Android解决方案被设计用于处理不同的使用场景,如处理实时摄像头feeds、视频文件以及静态图像。它还附带了一些实用工具,可以方便地将输出地标叠加到CPU图像(使用Canvas)或GPU(使用OpenGL)上。例如,下面的代码片段演示了如何使用它来处理实时摄像机feed并在屏幕上实时呈现输出:
// Creates MediaPipe Hands.
HandsOptions handsOptions =
HandsOptions.builder()
.setModelComplexity(1)
.setMaxNumHands(2)
.setRunOnGpu(true)
.build();
Hands hands = new Hands(activity, handsOptions);
// Connects MediaPipe Hands to camera.
CameraInput cameraInput = new CameraInput(activity);
cameraInput.setNewFrameListener(textureFrame -> hands.send(textureFrame));
// Registers a result listener.
hands.setResultListener(
handsResult -> {
handsView.setRenderData(handsResult);
handsView.requestRender();
})
// Starts the camera to feed data to MediaPipe Hands.
handsView.post(this::startCamera);
要了解更多关于MediaPipe Android解决方案的信息,请参阅相关的文档,并使用示例Android Studio项目尝试它们。还可以访问MediaPipe Solutions获取更多跨平台解决方案。
参考文章
https://lrting.top/backend/ai/2258/
https://blog.tensorflow.org/2021/11/3D-handpose.html?m=1