今回はHandsに触れてみようと思います。
MoveNetと似ている箇所が多いので、安心して取り組んでください。
Handsとは
Handsは、手の位置を検出し、各関節のランドマーク(指の位置)をリアルタイムで追跡するための機械学習モデルです。これは、カメラ映像や画像から手の形状や動きを捉え、最大で21個のランドマークポイントを特定します。
サイトにHandsを組み込む
最初に「Hands-1」というフォルダを作成しましょう。ここが作業場になります。そしてその配下に「index.html」「script.js」を作成します。
次にそれぞれのファイルのコードを記述していきます。下にあるコードをコピペして動作確認をします。
index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<!-- 3つのライブラリを読み込む -->
<script src="https://cdn.jsdelivr.net/npm/@mediapipe/camera_utils/camera_utils.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@mediapipe/drawing_utils/drawing_utils.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@mediapipe/hands/hands.js"></script>
<style>
/*ビデオとキャンバスを重ねるためのスタイル*/
#input, #output {
position: absolute;
top: 0;
left: 0;
}
#input {
z-index: 1;
}
#output {
z-index: 2;
}
</style>
</head>
<body>
<div class="container">
<!-- Webカメラの映像(入力) -->
<video id="input"autoplay"></video>
<!-- 認識した手の形状を可視化した映像(出力) -->
<canvas id="output" width="600" height="400"></canvas>
</div>
<script src="script.js"></script>
</body>
</html>
script.js
const video = document.getElementById('input');
const canvas = document.getElementById('output');
const ctx = canvas.getContext('2d');
const config = {
locateFile: file => `https://cdn.jsdelivr.net/npm/@mediapipe/hands/${file}`
};
const hands = new Hands(config);
const camera = new Camera(video, {
onFrame: async () => {
await hands.send({ image: video });
},
width: 600,
height: 400
});
camera.start();
hands.setOptions({
maxNumHands: 5,
modelComplexity: 1,
minDetectionConfidence: 0.5,
minTrackingConfidence: 0.5
});
hands.onResults(results => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
if (results.multiHandLandmarks) {
results.multiHandLandmarks.forEach(marks => {
// 緑色の線で骨組みを可視化
drawConnectors(ctx, marks, HAND_CONNECTIONS, { color: '#0f0' });
// 赤色でランドマークを可視化
drawLandmarks(ctx, marks, { color: '#f00' });
})
}
});
index.htmlを開いてください。うまくいくと、自分の手の上に赤い点と緑の線が表示されているはずです。
コード解説
hands.onResults(results => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
if (results.multiHandLandmarks) {
results.multiHandLandmarks.forEach(marks => {
// 緑色の線で骨組みを可視化
drawConnectors(ctx, marks, HAND_CONNECTIONS, { color: '#0f0' });
// 赤色でランドマークを可視化
drawLandmarks(ctx, marks, { color: '#f00' });
})
}
});
script.jsのresultsには画像を解析をした結果が入っています。results.multiHandLandmarksは手が認識できた場合にデータが入っています。
では、どのようなデータが入っているか見てみましょう。drawLandmarksの下に以下のコードを追加してください。
console.log(marks);
console.logはコンソール(出力画面)に出力します。print文と同じようなものです。F12を押し(右クリックをした後に検証を押し)Elementsの横にあるConsoleを押すと出力を見ることができます。
それぞれの数字は以下の画像に対応しています。

座標は0~1で取得されます。
課題
今回の課題は気づくことができれば簡単です。よく観察してみましょう。
- 緑の線を赤色に、赤色の点を緑色に変更しなさい。
- 人差し指の指先の座標によってコンソールに以下の文章を表示しなさい。
y座標が0.5以下の場合「上から来るぞ!気をつけろ!」
y座標が0.5より大きい場合「なんだこの階段はぁ!」
デスクリムゾンネタです。分からない人はすみません。
- marksは配列です。
- x、y、zはオブジェクトです。
drawConnectors(ctx, marks, HAND_CONNECTIONS, { color: '#f00' });
drawLandmarks(ctx, marks, { color: '#0f0' });
人差し指の指先は8です。なので、marks[8]と入力すると人差し指の指先の座標を取得することができます。また、y座標のみを取得するのでmarks[8].yと入力すると人差し指の指先のy座標を取得することができます。
if(marks[8].y<=0.5){
console.log("上から来るぞ!気をつけろ!");
}else{
console.log("なんだこの階段はぁ!");
}