使用@mediapipe/tasks-vision库在Vue中实现手势识别
MediaPipeTasksVision是MediaPipe提供的计算机视觉任务包,支持人脸检测、手势识别、图像分类等视觉任务。其特点包括易用性强、性能出色、跨平台支持等。示例代码展示了如何使用手势识别功能:通过加载预训练模型,获取摄像头视频流,实时检测手势类型和得分,并在画布上绘制手势关键点。该工具包还支持人脸特征点检测、人体姿态识别等多种功能,开发者可灵活调用API快速构建视觉应用。安装简单,
基本概念
MediaPipe Tasks Vision 是 MediaPipe 提供的一系列开箱即用的计算机视觉任务包,可帮助开发者快速构建高效的视觉应用,广泛应用于如人脸识别、手势识别、图像分割等领域。
主要功能
-
人脸检测 :能检测图像或视频中人脸的位置。
-
人脸特征点检测 :可精确定位人脸的关键特征点,方便后续处理。
-
人脸美颜 :对人脸进行美化处理,如磨皮、美白等。
-
手势识别 :实时识别手部手势,获取手势结果及手部关键点。
-
手部特征点检测 :检测手部在图像中的关键特征点,可渲染视觉特效。
-
人体姿态特征点检测 :结合姿态、人脸、手部特征点检测组件,实现人体特征点的完整检测。
-
图像分类 :识别图像所属的预定义类别。
-
图像嵌入 :从图像中提取嵌入。
-
图像分割 :将图像分割为不同类别。
-
目标检测 :检测图像或视频中多类目标的位置。
-
自拍分割 :将自拍图像分割为前景和背景。
特点
-
易用性强 :提供简洁的 API,无需深入了解底层实现细节,即可快速上手使用。
-
性能出色 :基于 MediaPipe 强大的框架,能高效处理各种视觉任务,满足实时性要求。
-
模型丰富 :涵盖多种预训练模型,适应不同场景和需求。
-
跨平台支持 :可在多种操作系统和设备上运行。
-
可扩展性好 :支持自定义模型和任务配置,开发者能根据实际需求灵活调整。
安装与使用
- npm i @mediapipe/tasks-vision
-
import { GestureRecognizer, FilesetResolver, DrawingUtils } from '@mediapipe/tasks-vision'
实现效果
可见,控制台打印了识别的到的手势类型,以及得分,实际中可以根据情况,对识别到的结果进行对应操作,比如握拳让页面滚动,实现赛博操控。

示例代码
HTML
<template>
<video id="webcam" width="640" height="480" autoplay></video>
<canvas id="output_canvas" width="640" height="480"></canvas>
</template>
Script
<script setup lang="ts">
import { GestureRecognizer, FilesetResolver, DrawingUtils } from '@mediapipe/tasks-vision';
import { ref, onMounted, nextTick } from 'vue'
// 手势识别器实例
let gestureRecognizer: any = null;
// 识别器识别的类型(图片/视频)
const runningMode = ref();
// 视频手势信息
const videoGestureInfo = ref<any>({});
// 手势枚举
const enumGesture: any = {
Closed_Fist: '握紧拳头',
Open_Palm: '张开手掌',
Thumb_Up: '竖起大拇指',
Thumb_Down: '拇指朝下',
Pointing_Up: '指向上',
Victory: '胜利',
None: '未识别',
};
// 创建手势识别器
const createGestureRecognizer = async () => {
// 加载指定版本的MediaPipe视觉任务WebAssembly模块
const vision = await FilesetResolver.forVisionTasks('https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@0.10.3/wasm');
// 创建了一个手势识别器实例(这个手势识别器实例使用的是指定版本的MediaPipe视觉任务WebAssembly模块)
gestureRecognizer = await GestureRecognizer.createFromOptions(vision, {
// 识别器配置
baseOptions: {
// 指向手势识别模型的路径
modelAssetPath: '/gesture_recognizer.task',
// 设置为GPU以尝试利用图形处理单元进行加速,提高模型推理的速度
delegate: 'GPU',
},
// 检测手掌的数量
numHands: 2,
});
console.log('手势识别器加载完毕');
// 识别视频中的手势
predictWebcam();
};
// 识别视频中的手势
const predictWebcam = async () => {
// 判断是否可以使用摄像头
if (!hasGetUserMedia()) return alert('此设备不允许使用摄像头!');
// 判断手势识别器是否加载完成
if (!gestureRecognizer) return alert('手势识别器未加载完成');
if (runningMode.value !== 'VIDEO') {
// 设置识别器识别的类型为视频
runningMode.value = 'VIDEO';
await gestureRecognizer.setOptions({ runningMode: runningMode.value });
}
await gestureRecognizer.setOptions({ numHands: 2 });
nextTick(() => {
// 获取video元素
const video = document.getElementById('webcam') as HTMLVideoElement;
// 获取视频手势节点绘制的canvas元素
const canvasElement = document.getElementById('output_canvas') as HTMLCanvasElement;
// 设置canvas的宽度和高度为video的宽度和高度
canvasElement.width = video.clientWidth;
canvasElement.height = video.clientHeight;
// 获取canvas的上下文
const canvasCtx = canvasElement.getContext('2d') as CanvasRenderingContext2D;
// 设置上次识别视频手势的时间
let lastVideoTime = -1;
// 识别视频中的手势
const predictWebcam = () => {
// 获取当前视频的时间
let nowInMs = Date.now();
let results: any = {};
// 如果视频的时间发生变化,则识别视频中的手势
if (video.currentTime !== lastVideoTime) {
// 替换上次识别视频手势的时间
lastVideoTime = video.currentTime;
results = gestureRecognizer.recognizeForVideo(video, nowInMs);
}
// 保存当前的canvas状态
canvasCtx.save();
// 清除canvas的内容
canvasCtx.clearRect(0, 0, canvasElement.width, canvasElement.height);
// 创建drawingUtils实例,用于可视化MediaPipeVision任务的结果
const drawingUtils = new DrawingUtils(canvasCtx);
// 判断是否识别到手势
if (results.landmarks) {
// 循环绘制手势的节点
for (const landmarks of results.landmarks) {
// 绘制手势连接线
drawingUtils.drawConnectors(landmarks, GestureRecognizer.HAND_CONNECTIONS, {
// 连接线的颜色
color: '#00FF00',
// 连接线的宽度
lineWidth: 3,
});
// 绘制手势关节点
drawingUtils.drawLandmarks(landmarks, {
// 关节点的颜色
color: '#FF0000',
// 关节点的半径
radius: 2.5,
});
}
}
// 恢复canvas的状态
canvasCtx.restore();
// 判断是否识别到手势数据
if (results?.gestures?.length > 0) {
videoGestureInfo.value.categoryName = enumGesture[results.gestures[0][0].categoryName];
videoGestureInfo.value.categoryScore = parseFloat(results.gestures[0][0].score * 100).toFixed(2);
videoGestureInfo.value.handedness = results.handednesses[0][0].displayName;
console.log('识别到的手势类别', videoGestureInfo.value.categoryName);
console.log('识别到的手势得分', videoGestureInfo.value.categoryScore);
} else {
videoGestureInfo.value.categoryName = '';
videoGestureInfo.value.categoryScore = '';
videoGestureInfo.value.handedness = '';
}
// 递归调用,继续识别视频中的手势
requestAnimationFrame(predictWebcam);
};
// 打开摄像头
navigator.mediaDevices.getUserMedia({ video: true }).then(stream => {
// 视频流添加到video元素中
video.srcObject = stream;
// 绑定视频加载完成事件,开始识别视频中的手势
video.addEventListener('loadeddata', predictWebcam);
});
});
};
// 判断是否可以使用摄像头
function hasGetUserMedia() {
return !!(navigator.mediaDevices && navigator.mediaDevices.getUserMedia);
}
onMounted(() => {
// 加载手势识别器
createGestureRecognizer();
});
</script>
其他
- 当然@mediapipe/tasks-vision的功能远不止于手势识别,像人脸识别,对象检测,面部实现也都支持,详情见@mediapipe/tasks-vision的npm地址
- 目前加载指定版本的MediaPipe视觉任务WebAssembly模块可能会出现加载失败,这与网络有关,属于正常。
- gesture_recognizer.task模型可以从官方地址获取,这里主包是下载到了本地方便使用。
更多推荐


所有评论(0)