WEBKT

TensorFlow.js手势识别:点赞与OK手势识别实战

130 0 0 0

TensorFlow.js手势识别:点赞与OK手势识别实战

本文将指导你如何使用 TensorFlow.js 构建一个简单的手势识别应用,可以识别“点赞”和“OK”手势,并根据识别结果触发相应的事件。我们将提供详细的步骤说明和代码示例,帮助你快速上手。

准备工作

  1. 安装 TensorFlow.js: 首先,你需要安装 TensorFlow.js。你可以通过 npm 安装,也可以直接在 HTML 文件中引入 CDN 链接。

    • npm 安装:

      npm install @tensorflow/tfjs
      
    • CDN 引入:

      <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@latest"></script>
      
  2. 准备训练数据: 我们需要准备一些“点赞”和“OK”手势的图像数据用于训练模型。你可以自己拍摄照片,也可以从网上搜索。为了获得更好的识别效果,建议收集尽可能多的数据,并保证数据的多样性(例如,不同光照条件、不同角度、不同背景等)。

  3. 数据标注: 你需要对收集到的数据进行标注,即标记每张图片属于哪个手势。可以使用图像标注工具,例如 LabelImg。标注完成后,你将获得一个包含图像路径和对应标签的文件。

代码实现

1. 数据加载与预处理

首先,我们需要加载训练数据,并对其进行预处理。预处理包括:

  • 图像大小调整: 将所有图像调整到统一的大小,例如 64x64 像素。
  • 图像归一化: 将像素值缩放到 0-1 之间。
  • 标签编码: 将文本标签(例如“点赞”、“OK”)转换为数字编码(例如 0、1)。
import * as tf from '@tensorflow/tfjs';

// 加载数据
async function loadData(dataPath) {
  const response = await fetch(dataPath);
  const data = await response.json();
  return data;
}

// 图像预处理
async function preprocessImage(imagePath) {
  return new Promise((resolve, reject) => {
    const img = new Image();
    img.onload = () => {
      // 使用 tf.browser.fromPixels 从图像元素创建张量
      const tensor = tf.browser.fromPixels(img)
        .resizeNearestNeighbor([64, 64]) // 调整大小
        .toFloat()                      // 转换为浮点型
        .div(tf.scalar(255.0));       // 归一化
      resolve(tensor);
    };
    img.onerror = reject;
    img.src = imagePath;
  });
}

// 准备训练数据
async function prepareData(dataPath) {
  const data = await loadData(dataPath);
  const images = [];
  const labels = [];

  for (const item of data) {
    const imageTensor = await preprocessImage(item.image);
    images.push(imageTensor);
    labels.push(item.label === 'like' ? 0 : 1); // 标签编码
  }

  // 将图像数据和标签转换为张量
  const xs = tf.stack(images);
  const ys = tf.oneHot(tf.tensor1d(labels, 'int32'), 2);

  return { xs, ys };
}

2. 构建模型

接下来,我们需要构建一个卷积神经网络 (CNN) 模型,用于手势识别。一个简单的 CNN 模型可以包含以下几层:

  • 卷积层 (Conv2D)
  • 最大池化层 (MaxPooling2D)
  • Flatten 层
  • 全连接层 (Dense)
// 构建模型
function createModel() {
  const model = tf.sequential();

  model.add(tf.layers.conv2d({
    inputShape: [64, 64, 3], // 输入图像大小
    filters: 32,           // 卷积核数量
    kernelSize: 3,        // 卷积核大小
    activation: 'relu',      // 激活函数
  }));
  model.add(tf.layers.maxPooling2d({ poolSize: [2, 2] }));
  model.add(tf.layers.conv2d({
    filters: 64,
    kernelSize: 3,
    activation: 'relu',
  }));
  model.add(tf.layers.maxPooling2d({ poolSize: [2, 2] }));
  model.add(tf.layers.flatten());
  model.add(tf.layers.dense({ units: 128, activation: 'relu' }));
  model.add(tf.layers.dense({ units: 2, activation: 'softmax' })); // 输出层,2个类别(点赞、OK)

  return model;
}

3. 训练模型

构建好模型后,我们需要使用准备好的训练数据来训练模型。在训练过程中,我们需要指定损失函数、优化器和评估指标。

// 训练模型
async function trainModel(model, xs, ys) {
  model.compile({
    optimizer: 'adam',
    loss: 'categoricalCrossentropy',
    metrics: ['accuracy'],
  });

  const history = await model.fit(xs, ys, {
    epochs: 10,
    validationSplit: 0.2,
    callbacks: tf.callbacks.earlyStopping({ monitor: 'val_loss', patience: 3 }),
  });

  console.log(history);
}

4. 模型评估

训练完成后,我们需要使用测试数据来评估模型的性能。常用的评估指标包括准确率、精确率、召回率和 F1 值。

// 评估模型
async function evaluateModel(model, xs, ys) {
  const results = await model.evaluate(xs, ys);
  console.log('Loss:', results[0].dataSync()[0]);
  console.log('Accuracy:', results[1].dataSync()[0]);
}

5. 手势识别与事件触发

最后,我们需要将训练好的模型集成到 Web 应用中,并实现手势识别和事件触发功能。可以使用摄像头实时捕获图像,然后将图像输入到模型中进行预测,并根据预测结果触发相应的事件。

// 预测手势
async function predictGesture(model, imageElement) {
  const tensor = tf.browser.fromPixels(imageElement)
    .resizeNearestNeighbor([64, 64])
    .toFloat()
    .div(tf.scalar(255.0))
    .expandDims(); // 增加一个维度,因为模型需要一个批次

  const prediction = await model.predict(tensor).data();
  const likeProbability = prediction[0];
  const okProbability = prediction[1];

  if (likeProbability > okProbability) {
    return 'like';
  } else {
    return 'ok';
  }
}

// 事件触发
async function triggerEvent(gesture) {
  if (gesture === 'like') {
    // 触发点赞事件
    console.log('点赞!');
    // 在这里添加你的点赞事件处理代码
  } else if (gesture === 'ok') {
    // 触发 OK 事件
    console.log('OK!');
    // 在这里添加你的 OK 事件处理代码
  }
}

// 从摄像头获取图像并进行预测
async function runGestureRecognition(model, videoElement) {
  async function frameIteration() {
    const gesture = await predictGesture(model, videoElement);
    await triggerEvent(gesture);
    requestAnimationFrame(frameIteration);
  }
  frameIteration();
}

// 初始化
async function init() {
  const model = createModel();
  const { xs, ys } = await prepareData('data.json'); // 假设数据保存在 data.json 文件中
  await trainModel(model, xs, ys);

  const videoElement = document.getElementById('webcam');
  navigator.mediaDevices.getUserMedia({ video: true })
    .then((stream) => {
      videoElement.srcObject = stream;
      videoElement.onloadedmetadata = () => {
        videoElement.play();
        runGestureRecognition(model, videoElement);
      };
    });
}

init();

HTML 结构

为了配合JavaScript代码,需要一个简单的HTML结构,包含一个用于显示摄像头画面的video元素:

<!DOCTYPE html>
<html>
<head>
  <title>TensorFlow.js Gesture Recognition</title>
  <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@latest"></script>
</head>
<body>
  <video id="webcam" width="640" height="480" autoplay muted></video>
  <script src="script.js"></script>
</body>
</html>

总结

本文介绍了如何使用 TensorFlow.js 构建一个简单的手势识别应用。通过这个例子,你可以了解 TensorFlow.js 的基本用法,并将其应用到更复杂的场景中。 需要注意的是,这只是一个简单的示例,实际应用中可能需要更复杂的模型和更多的数据来获得更好的识别效果。

改进方向

  • 增加数据量: 收集更多的数据,特别是不同光照条件、不同角度、不同背景下的数据。
  • 优化模型: 尝试不同的模型结构和参数,例如更深的网络、更大的卷积核等。
  • 使用数据增强: 使用数据增强技术,例如旋转、缩放、平移等,来增加数据的多样性。
  • 加入更多手势: 扩展模型,使其能够识别更多的手势。
  • 优化性能: 使用 WebGL 后端来加速模型推理。

通过不断改进,你可以构建一个更加准确、鲁棒和实用的手势识别应用。

码农小飞 TensorFlow.js手势识别机器学习

评论点评