本文作者系360奇舞团前端开发工程师
一 介绍
Handsfree是一个通过计算机视觉集成手势,面部表情和各种姿势识别的前端库。其核心ai技术用到了tensorflow,可在浏览器上触发交互事件,比如滚动网页,检测人脸并展示相关表情,控制桌面游戏。也可以通过websocket接口控制任意与电脑连接的设备。
原来这个库有详细的文档和相关代码示例,但不清楚为什么最近都找不到了,作者也很多年没有更新了,这个库使用起来比较简单,所以抽时间整理下,也有相关其他库可替代,比如Handtrack.js,用来检测人手部动作。
官网截图
二 使用方法
初始化
-
在 DOM 中包含 Handsfree.js JavaScript 和样式表即可。
ini<link rel="stylesheet" href="https://unpkg.com/handsfree@8.5.1/build/lib/assets/handsfree.css" /> <script src="https://unpkg.com/handsfree@8.5.1/build/lib/handsfree.js"></script>
引用后会将
Handsfree
类以及指针的基本样式添加到页面中。下一步是创建一个实例Handsfree
:arduinoconst config = { showDebug: true, hands: true } const handsfree = new Handsfree(config) handsfree.start()
-
使用npm
phpnpm i handsfree handsfree = new Handsfree({ showDebug: true, hands: { enabled: true } }) handsfree.start()
Handsfree.js 提供了几种方法。两个主要的方法是 start() 和 stop(),分别用于加载检测模型和获取预测结果。
handsfree可添加插件,例如下面的 consoleLogger
,可打印instance实例,获取很多有用信息的属性。
javascript
handsfree.start()
handsfree.use('consoleLogger', (instance) => {
console.log(instance.head.pointer.x)
console.log(instance.head.pointer.y)
})
元素类名
当页面状态发生变化的时候,body标签会自动加上class类名,或者加上显隐状态
csharp
handsfree-show-when-stopped handsfree-hide-when-loading // 默认隐藏loading,没有开启时展示开始按钮
handsfree-show-when-started handsfree-hide-when-loading // 默认隐藏loading,当开始运行时展示停止按钮
三 代码示例
可复制代码在电脑跑下看看效果,开启摄像头权限后,用手捏住上下滑动即可滑动对应的dom节点背景图。
xml
<head>
<!-- Include Handsfree.js -->
<link rel="stylesheet" href="https://unpkg.com/handsfree@8.5.1/build/lib/assets/handsfree.css" />
<script src="https://unpkg.com/handsfree@8.5.1/build/lib/handsfree.js"></script>
<style>
.handsfree-canvas-video {
background: #000;
opacity: 0.1;
}
</style>
</head>
<body>
<!-- Start/stop button with helper classes -->
<div class="text-center">
<button class="handsfree-show-when-stopped handsfree-hide-when-loading" onclick="toggleModel('hands')">Start Hand Tracking</button>
<button class="handsfree-show-when-loading" disabled>Loading ...</button>
<button class="handsfree-show-when-started handsfree-hide-when-loading" onclick="handsfree.stop()">Stop Handsfree</button>
</div>
<!-- Pincher table with helper classes to toggle things on/off -->
<section>
<h1>Pinch fingers and drag to scroll the area under the pointers.</h1>
<table class="multi-hand-scrollers">
<tr>
<td width="50%"><div><div></div></div></td>
<td width="50%"><div><div></div></div></td>
</tr>
<tr>
<td width="50%"><div><div></div></div></td>
<td width="50%"><div><div></div></div></td>
</tr>
</table>
<!-- We'll have the debugger injected into here -->
<div id="debugger-holder"></div>
</section>
<!-- Instantiate and start it -->
<script>
const handsfree = new Handsfree({
showDebug: true,
setup: {
wrap: {
$parent: document.querySelector('#debugger-holder')
}
}
})
handsfree.enablePlugins('browser')
function toggleModel(name) {
const config = {}
config[name] = !handsfree.model[name].enabled
config.autostart = true
handsfree.update(config)
}
</script>
<!-- Demo styles -->
<style>
button {
font-size: 1em;
padding: .5em;
}
h1, table {
margin-top: 60px;
}
section {
width: 800px;
max-width: 100%;
margin: auto;
}
table {
width: 100%
}
.finger-pincher {
display: inline-block;
width: 32px;
height: 32px;
border-radius: 32px;
background: #000;
margin: auto;
}
.finger-pincher:last-child {
background: #f00;
}
.text-center {
text-align: center;
}
table {
width: 100%;
display: table;
table-layout: fixed;
}
.multi-hand-scrollers td {
padding: 0;
}
.multi-hand-scrollers td > div {
max-height: 300px;
overflow: auto;
}
.multi-hand-scrollers td > div > div {
height: 1000px;
width: 1000px;
background: url("https://i.imgur.com/W4ja4fR.png");
background-repeat: space;
background-size: 32px;
opacity: 0.25;
}
</style>
</body>
滚动页面.gif
作者的其他示例
四 局限性
浏览器是单线程的:所以必须确保预测操作不会阻塞 UI 线程。每个预测可能需要 50 到 150 毫秒,所以用户会注意到这个延迟。
逐帧跟踪手部动作:如果想要跨帧识别手势,需要编写额外的代码来推断手在进入、移动和离开连续帧时的 ID。
不正确的预测:偶尔会出现不正确的预测(有时候会将脸检测为手)或者同时捏住三根手指的时候无法正确判断。而且不同的摄像头和光线条件都需要不同的模型参数设置(尤其是置信度阈值)才能获得良好的检测效果。