2
3

ヒューマノイドロボットをwebカメラの骨格推定で操作するゲーム。

Last updated at Posted at 2024-09-15

ヒューマノイドロボットをwebカメラの骨格推定で操作するゲーム。

webカメラの骨格推定で操作します。
スクリーンショット 2024-09-16 042545.png

スクリーンショット 2024-09-16 042531.png

スクリーンショット 2024-09-16 042613.png

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>3D骨格推定と背景緑色設定</title>
  <!-- TensorFlow.jsとPoseNetの読み込み -->
  <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs"></script>
  <script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/posenet"></script>
  <!-- Three.jsの読み込み -->
  <script src="https://cdn.jsdelivr.net/npm/three@0.135.0/build/three.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/three@0.135.0/examples/js/controls/OrbitControls.js"></script>

  <style>
    body { margin: 0; overflow: hidden; }
    canvas { display: block; background-color: green; } /* 背景を緑色に設定 */
  </style>
</head>
<body>
  <video id="video" width="640" height="480" autoplay style="display:none;"></video>
  
  <script>
    let scene, camera, renderer;
    
    // Three.jsの初期化
    function initThreeJS() {
      scene = new THREE.Scene();
      camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
      renderer = new THREE.WebGLRenderer();
      renderer.setSize(window.innerWidth, window.innerHeight);
      document.body.appendChild(renderer.domElement);
      
      // カメラの位置を設定
      camera.position.z = 5;
      
      // ライトの追加
      const light = new THREE.DirectionalLight(0xffffff, 1);
      light.position.set(0, 1, 1).normalize();
      scene.add(light);
      
      // オービットコントロールの追加
      const controls = new THREE.OrbitControls(camera, renderer.domElement);
    }

    // 骨格データを描画する
    function drawSkeletonOnThreeJS(keypoints) {
      // 既存の骨格を削除
      const existingSpheres = scene.children.filter(child => child.type === 'Mesh' && child.geometry.type === 'SphereGeometry');
      existingSpheres.forEach(sphere => scene.remove(sphere));

      const existingLines = scene.children.filter(child => child.type === 'Line');
      existingLines.forEach(line => scene.remove(line));

      // 骨格のラインを描画
      const adjacentKeyPoints = posenet.getAdjacentKeyPoints(keypoints, 0.5);
      adjacentKeyPoints.forEach(keypointsPair => {
        const [start, end] = keypointsPair;
        if (start.score > 0.5 && end.score > 0.5) {
          const material = new THREE.LineBasicMaterial({ color: 0xffffff });
          const geometry = new THREE.BufferGeometry().setFromPoints([
            new THREE.Vector3((start.position.x - video.width / 2) / 100, -(start.position.y - video.height / 2) / 100, 0),
            new THREE.Vector3((end.position.x - video.width / 2) / 100, -(end.position.y - video.height / 2) / 100, 0)
          ]);
          const line = new THREE.Line(geometry, material);
          scene.add(line);
        }
      });

      // 骨格の各点を描画
      keypoints.forEach(keypoint => {
        if (keypoint.score > 0.5) {
          const { y, x } = keypoint.position;
          const z = 0; // Z軸方向の位置を仮に0とする

          let color;
          if (keypoint.part === 'nose') color = 0x0000ff; // 青
          else if (keypoint.part.includes('leftWrist') || keypoint.part.includes('rightWrist')) color = 0xff0000; // 赤
          else color = 0xffffff; // その他のパーツ

          const geometry = new THREE.SphereGeometry(0.1, 32, 32);
          const material = new THREE.MeshBasicMaterial({ color: color });
          const sphere = new THREE.Mesh(geometry, material);
          sphere.position.set((x - video.width / 2) / 100, -(y - video.height / 2) / 100, z);
          scene.add(sphere);
        }
      });
    }

    // アニメーションループ
    function animate() {
      requestAnimationFrame(animate);
      renderer.render(scene, camera);
    }

    // カメラの映像を取得してPoseNetで骨格推定を行う
    async function startPoseNet() {
      const video = document.getElementById('video');

      // カメラにアクセス
      navigator.mediaDevices.getUserMedia({
        video: true
      }).then(stream => {
        video.srcObject = stream;
      });

      // PoseNetモデルのロード
      const net = await posenet.load();

      video.onloadeddata = async () => {
        // 骨格推定と描画を繰り返し実行
        setInterval(async () => {
          const pose = await net.estimateSinglePose(video, {
            flipHorizontal: false
          });

          drawSkeletonOnThreeJS(pose.keypoints);
        }, 100);
      };
    }

    // 初期化とアニメーション開始
    initThreeJS();
    animate();
    startPoseNet();
  </script>
</body>
</html>

3D骨格推定システムの実装。

  1. はじめに
    本研究では、Web技術を利用してリアルタイムの3D骨格推定を実現するシステムを提案する。特に、Three.jsおよびTensorFlow.jsのPoseNetモデルを用いた実装に焦点を当てる。システムは、ユーザーのWebカメラから取得した画像を解析し、骨格の3D表示を行う。この際、背景色を緑に設定し、視覚的に骨格推定の結果を強調する。

  2. システムの設計と実装
    2.1 Three.jsによる3Dシーンの初期化

Three.jsライブラリを使用して3Dシーンを構築する。システムの初期化では、以下の要素を設定する:

シーン (scene): 3Dオブジェクトを描画する空間を定義する。
カメラ (camera): 視点を設定するための透視カメラを配置し、Z軸方向に位置を設定する。
レンダラー (renderer): WebGLを利用してシーンを描画するレンダラーを設定する。

2.2 背景色の設定

背景色を緑色に設定するために、CSSのbackground-colorプロパティを使用する。これにより、3Dシーンの視覚的な効果が向上し、骨格推定結果がより際立つ。

2.3 骨格推定データの描画

PoseNetモデルを利用して、Webカメラから取得した画像の骨格を推定し、Three.jsのシーンに描画する。

骨格推定結果は、各関節を球体で表示し、関節間を線で結ぶ。以下の手順で実装される:

キーポイントの表示: 各関節(キーポイント)を球体で描画し、特定の関節に応じて色分けする。
骨格のライン描画: 関節間を線で結び、骨格の構造を視覚化する。

2.4 PoseNetによるリアルタイム骨格推定

Webカメラからの映像を取得し、PoseNetモデルを用いてリアルタイムで骨格推定を行う。推定結果は一定間隔で更新され、Three.jsのシーンに描画される。

  1. 結果
    本システムは、Webカメラを用いてリアルタイムで骨格推定を行い、その結果を3D空間に描画する機能を提供する。システムの実装により、ユーザーの動きや姿勢を3Dで可視化し、インタラクティブな体験を提供する。

  2. 結論
    本研究で提案したシステムは、Three.jsとPoseNetを組み合わせることで、Webベースの3D骨格推定と表示を実現した。背景色の設定と骨格の視覚化により、ユーザーは直感的に骨格データを理解することができる。今後の研究では、さらに複雑な骨格推定モデルや追加機能の統合を検討する予定である。

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3