欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JavaScript實現(xiàn)手勢識別的示例詳解

 更新時間:2024年12月24日 11:00:46   作者:小噔小咚什么東東  
這篇文章主要為大家詳細(xì)介紹了JavaScrip如何利用?TensorFlow.js?中的?HandPose?模型,實現(xiàn)一個基于視頻流的手勢識別系統(tǒng),感興趣的可以了解下

利用 TensorFlow.js 中的 HandPose 模型,實現(xiàn)一個基于視頻流的手勢識別系統(tǒng),通過 HTML5 視頻流獲取攝像頭數(shù)據(jù),并結(jié)合 HandPose 模型來識別用戶的手勢。最終的目標(biāo)是能夠通過攝像頭實時識別并顯示手指數(shù)量的手勢。

項目概述

這個項目的實現(xiàn)包括以下幾個步驟:

  • 獲取視頻流并設(shè)置攝像頭。
  • 加載 HandPose 模型,并顯示加載進(jìn)度。
  • 通過模型識別手勢。
  • 基于手指的狀態(tài)輸出對應(yīng)的手勢數(shù)字(例如“1”代表一個手指,“2”代表兩個手指等)。

獲取視頻流并設(shè)置攝像頭

首先,需要通過瀏覽器的 navigator.mediaDevices.getUserMedia API 獲取用戶的攝像頭視頻流,并在網(wǎng)頁上顯示該視頻流。具體代碼如下:

async function setupCamera() {
  const video = document.getElementById('video');
  const stream = await navigator.mediaDevices.getUserMedia({
    video: true,
  });
  video.srcObject = stream;

  return new Promise((resolve) => {
    video.onloadedmetadata = () => {
      resolve(video);
    };
  });
}

此函數(shù)將視頻流顯示在 HTML 中的 <video> 元素上,并在視頻加載完成后返回該視頻元素。

加載 HandPose 模型并顯示加載進(jìn)度

為了進(jìn)行手勢識別,我們需要加載 TensorFlow.js 提供的 HandPose 模型。HandPose 模型是一個用于估計手部關(guān)鍵點位置的深度學(xué)習(xí)模型,可以幫助我們識別手的姿勢。 在加載 HandPose 模型時,我們希望顯示加載進(jìn)度。這是通過 progressCallback 實現(xiàn)的,它會在每次加載進(jìn)度更新時觸發(fā):

async function loadHandPoseModel() {
  const loadingContainer = document.getElementById('loading-container');
  loadingContainer.style.display = 'block'; // 顯示加載進(jìn)度條

  const model = await handpose.load({
    flipHorizontal: false,  // 不要水平翻轉(zhuǎn)模型
    progressCallback: (fraction) => {
      const progress = Math.round(fraction * 100); // 計算加載的百分比
      showLoadingProgress(progress); // 更新進(jìn)度條
    }
  });

  loadingContainer.style.display = 'none'; // 隱藏加載進(jìn)度條
  return model;
}

通過此函數(shù),可以實時展示模型加載的進(jìn)度條,提升用戶體驗。

識別手勢

在加載完 HandPose 模型之后,我們就可以使用該模型來識別手勢了。模型會估計手部的 21 個關(guān)鍵點位置,并通過這些關(guān)鍵點來推測手指是否伸展。 我們需要遍歷這些關(guān)鍵點,分析每個手指是否伸出。如果手指的末端關(guān)鍵點(例如食指末端)高于相鄰的關(guān)節(jié)點,表示該手指伸展。通過此邏輯,我們可以判斷用戶伸出的手指數(shù)量:

function detectFingers(landmarks) {
  let fingers = 0;

  // 判斷每根手指的伸展情況
  const thumb = landmarks[4];  // 拇指
  const index = landmarks[8];  // 食指
  const middle = landmarks[12];  // 中指
  const ring = landmarks[16];  // 無名指
  const pinky = landmarks[20];  // 小拇指

  if (index[1] < thumb[1]) fingers++;  // 食指伸展
  if (middle[1] < index[1]) fingers++;  // 中指伸展
  if (ring[1] < middle[1]) fingers++;  // 無名指伸展
  if (pinky[1] < ring[1]) fingers++;  // 小拇指伸展

  return fingers;
}

通過此函數(shù),能夠判斷出當(dāng)前用戶伸出的手指數(shù)量。

輸出手勢結(jié)果

通過識別出的手指數(shù)量,我們可以展示一個對應(yīng)的數(shù)字手勢。例如,如果用戶伸出一個手指,我們顯示“1”;如果伸出兩個手指,則顯示“2”,依此類推。手勢識別結(jié)果會實時更新在網(wǎng)頁上:

async function detectGesture(video, model) {
  const predictions = await model.estimateHands(video);

  // 如果沒有檢測到手部,則顯示"檢測中..."
  if (predictions.length === 0) {
    document.getElementById('result').innerText = "檢測中...";
    requestAnimationFrame(() => detectGesture(video, model));
    return;
  }

  const landmarks = predictions[0].landmarks; // 獲取手部的關(guān)鍵點
  const fingers = detectFingers(landmarks);

  let resultText = "檢測中...";

  // 基于手指的狀態(tài)判斷手勢
  switch (fingers) {
    case 1:
      resultText = "一";
      break;
    case 2:
      resultText = "二";
      break;
    case 3:
      resultText = "三";
      break;
    case 4:
      resultText = "四";
      break;
    case 5:
      resultText = "五";
      break;
    default:
      resultText = "無法識別手勢";
      break;
  }

  // 更新檢測結(jié)果顯示
  document.getElementById('result').innerText = resultText;

  // 每一幀進(jìn)行檢測
  requestAnimationFrame(() => detectGesture(video, model));
}

每一幀都會重新檢測手勢,以確保輸出實時更新。

整合所有部分

最后,將所有的功能整合在一起,啟動視頻流并開始手勢識別:

async function main() {
  // 等待模型加載
  const model = await loadHandPoseModel();
  
  // 設(shè)置視頻流并開始播放
  const video = await setupCamera();
  video.play();

  // 開始手勢識別
  detectGesture(video, model);
}

main();

通過以上步驟,實現(xiàn)了一個基于 HandPose 模型的手勢識別系統(tǒng)。利用瀏覽器提供的 getUserMedia API 獲取視頻流,并通過 TensorFlow.js 提供的 HandPose 模型來估計手的關(guān)鍵點,最終實現(xiàn)了對手勢的實時識別。

完整代碼

// 顯示加載進(jìn)度條
function showLoadingProgress(progress) {
  const progressBar = document.getElementById('progress');
  progressBar.style.width = progress + '%';
}

// 1. 獲取視頻流并設(shè)置攝像頭
async function setupCamera() {
  const video = document.getElementById('video');
  const stream = await navigator.mediaDevices.getUserMedia({
    video: true,
  });
  video.srcObject = stream;

  return new Promise((resolve) => {
    video.onloadedmetadata = () => {
      resolve(video);
    };
  });
}

// 2. 加載 HandPose 模型并顯示加載進(jìn)度
async function loadHandPoseModel() {
  const loadingContainer = document.getElementById('loading-container');
  loadingContainer.style.display = 'block'; // 顯示加載進(jìn)度條

  const model = await handpose.load({
    flipHorizontal: false,  // 不要水平翻轉(zhuǎn)模型
    progressCallback: (fraction) => {
      const progress = Math.round(fraction * 100); // 計算加載的百分比
      showLoadingProgress(progress); // 更新進(jìn)度條
    }
  });

  loadingContainer.style.display = 'none'; // 隱藏加載進(jìn)度條
  return model;
}

// 3. 識別手勢
async function detectGesture(video, model) {
  const predictions = await model.estimateHands(video);

  // 如果沒有檢測到手部,則顯示"檢測中..."
  if (predictions.length === 0) {
    document.getElementById('result').innerText = "檢測中...";
    requestAnimationFrame(() => detectGesture(video, model));
    return;
  }

  const landmarks = predictions[0].landmarks; // 獲取手部的關(guān)鍵點
  const fingers = detectFingers(landmarks);

  let resultText = "檢測中...";

  // 基于手指的狀態(tài)判斷手勢
  switch (fingers) {
    case 1:
      resultText = "一";
      break;
    case 2:
      resultText = "二";
      break;
    case 3:
      resultText = "三";
      break;
    case 4:
      resultText = "四";
      break;
    case 5:
      resultText = "五";
      break;
    default:
      resultText = "無法識別手勢";
      break;
  }

  // 更新檢測結(jié)果顯示
  document.getElementById('result').innerText = resultText;

  // 每一幀進(jìn)行檢測
  requestAnimationFrame(() => detectGesture(video, model));
}

// 4. 判斷手勢
function detectFingers(landmarks) {
  let fingers = 0;

  // 判斷每個手指是否伸出:如果手指的末端關(guān)鍵點在其他關(guān)鍵點的上方,說明該手指伸出
  // 對于每根手指,檢查其關(guān)鍵點位置
  // 手指順序: [1: thumb, 2: index, 3: middle, 4: ring, 5: pinky]

  // 檢查每根手指的伸展情況
  const thumb = landmarks[4];  // 拇指
  const index = landmarks[8];  // 食指
  const middle = landmarks[12];  // 中指
  const ring = landmarks[16];  // 無名指
  const pinky = landmarks[20];  // 小拇指

  if (index[1] < thumb[1]) fingers++;  // 如果食指的末端在拇指的末端前面,說明食指伸展
  if (middle[1] < index[1]) fingers++;  // 如果中指的末端在食指的末端前面,說明中指伸展
  if (ring[1] < middle[1]) fingers++;  // 如果無名指的末端在中指的末端前面,說明無名指伸展
  if (pinky[1] < ring[1]) fingers++;  // 如果小拇指的末端在無名指的末端前面,說明小拇指伸展

  // 在"四"和"五"的判斷上,可以加大判斷容忍度,避免誤判
  if (ring[1] < middle[1] && pinky[1] < ring[1]) {
    // 可能"四"或者"五"的手勢識別較弱,可以通過容忍度來改進(jìn)
    fingers = (fingers === 4) ? 5 : fingers;
  }

  return fingers;
}

async function main() {
  // 等待模型加載
  const model = await loadHandPoseModel();
  
  // 設(shè)置視頻流并開始播放
  const video = await setupCamera();
  video.play();

  // 開始手勢識別
  detectGesture(video, model);
}

main();

html 文件

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>手勢識別</title>
  <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs"></script>
  <script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/handpose"></script>
  <script src="https://unpkg.com/@tensorflow/tfjs-backend-webgl"></script>
</head>
<body>
  <h1>手勢識別</h1>
  <video id="video" width="640" height="480" autoplay></video>
  <div id="result">檢測中...</div>

  <div id="loading-container">
    <div id="progress-bar">
      <div id="progress"></div>
    </div>
    <div id="loading-text">正在加載模型...</div>
  </div>

  <script src="app.js"></script>
</body>
</html>

效果展示

到此這篇關(guān)于JavaScript實現(xiàn)手勢識別的示例詳解的文章就介紹到這了,更多相關(guān)JavaScript手勢識別內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論