Geminiと一緒にコードを書くとき、「Canvas」機能がとても便利ですよね。
実はこのCanvas、カメラを使ったWebアプリもそのまま動きます。しかも、MediaPipeを使ったハンドジェスチャー認識もOK!
ただし、動かすにはちょっとしたコツがあったので、この記事で紹介します。
できあがるアプリのイメージ
- カメラに手をかざすと、MediaPipeがジェスチャーを認識
- Victory: ピースサイン ✌️
- Thumb_Up: サムズアップ 👍
- Thumb_Down: サムズダウン 👎
- Pointing_Up: 指差し(上) ☝️
- Closed_Fist: 握りこぶし ✊
- Open_Palm: 手のひらを開く 🖐️
- ILoveYou: "I Love You" のサイン 🤟
- オプションで手の骨格を描画する機能あり
- GeminiのCanvasでもそのまま動作!
Geminiに「この記事のコードをベースに改造して」とお願いすれば、手戻りなくスムーズに開発が始められます。
スターターコード
以下のHTMLを index.html
として保存し、VSCodeのLive Serverなどで開くだけで動きます。
👇 Gemini Canvas上でも動作確認済みです!
ソースコード
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>MediaPipeジェスチャー認識 スターターキット</title>
<style>
body { font-family: sans-serif; display: flex; flex-direction: column; align-items: center; margin: 0; padding: 1rem; background-color: #f0f0f0; }
h1 { margin-top: 0; }
#output { font-size: 1.5rem; font-weight: bold; margin: 0.5rem; color: #007bff; min-height: 2.5rem; }
.video-container { position: relative; width: 640px; height: 480px; }
video, canvas {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border-radius: 8px;
}
video {
border: 2px solid #ccc;
transform: scaleX(-1); /* ユーザーが鏡を見るように映像を左右反転 */
}
.controls { margin-top: 1rem; display: flex; align-items: center; gap: 1rem; }
button {
padding: 0.5rem 1rem;
font-size: 1rem;
cursor: pointer;
border-radius: 5px;
border: 1px solid #ccc;
}
button:disabled { cursor: not-allowed; background-color: #e0e0e0; }
</style>
</head>
<body>
<h1>MediaPipe ジェスチャー認識</h1>
<p>下のボタンを押してカメラを開始してください</p>
<div id="output">準備中...</div>
<div class="video-container">
<video id="webcam" autoplay playsinline></video>
<canvas id="skeleton_canvas"></canvas>
</div>
<div class="controls">
<button id="camera_button" disabled>カメラを開始</button>
<label>
<input type="checkbox" id="skeleton_checkbox">
骨格を表示
</label>
</div>
<script type="module">
// MediaPipeのAI機能をブラウザで使うためのライブラリを読み込みます
// ライブラリーのバージョンをtasks-vision@0.10.3のように指定すると動作しません。
import {
GestureRecognizer,
FilesetResolver,
DrawingUtils
} from "https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision/vision_bundle.js";
// HTMLから要素を取得し、後でJavaScriptから操作できるようにします
const video = document.getElementById("webcam");
const outputDiv = document.getElementById("output");
const cameraButton = document.getElementById("camera_button");
const skeletonCheckbox = document.getElementById("skeleton_checkbox");
const canvasElement = document.getElementById("skeleton_canvas");
const canvasCtx = canvasElement.getContext("2d");
// アプリケーション全体で使う変数を準備します
let gestureRecognizer; // ジェスチャー認識を行うAIモデルのインスタンス
let webcamRunning = false; // カメラが作動中か管理するフラグ
let drawingUtils; // 骨格などを描画するための補助ツール
// MediaPipeのAIモデルを非同期で初期化するメイン処理
async function initializeMediaPipe() {
// AIモデルが必要とする追加ファイルを読み込む準備
// ライブラリーのバージョンをtasks-vision@0.10.3のように指定すると動作しません。
const vision = await FilesetResolver.forVisionTasks(
"https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision/wasm"
);
// ジェスチャー認識モデル本体をダウンロードし、設定を行います
gestureRecognizer = await GestureRecognizer.createFromOptions(vision, {
baseOptions: {
modelAssetPath: "https://storage.googleapis.com/mediapipe-models/gesture_recognizer/gesture_recognizer/float16/1/gesture_recognizer.task",
delegate: "GPU" // 可能であればGPUを使って処理を高速化します
},
runningMode: "VIDEO", // ビデオ映像をリアルタイムで処理するモード
numHands: 2 // 同時に認識する手の最大数
});
// 初期化が完了したらUIを更新します
outputDiv.innerText = "準備完了";
cameraButton.disabled = false;
drawingUtils = new DrawingUtils(canvasCtx);
}
// ページが読み込まれたら、AIモデルの初期化を開始します
initializeMediaPipe();
// カメラの開始/停止ボタンが押されたときの処理
async function toggleWebcam() {
if (!gestureRecognizer) return; // モデルが準備できていなければ何もしない
if (webcamRunning) {
// カメラを停止する処理
webcamRunning = false;
cameraButton.innerText = "カメラを開始";
video.srcObject.getTracks().forEach(track => track.stop());
video.srcObject = null;
outputDiv.innerText = "停止中";
canvasCtx.clearRect(0, 0, canvasElement.width, canvasElement.height);
} else {
// カメラを開始する処理
webcamRunning = true;
cameraButton.innerText = "カメラを停止";
outputDiv.innerText = "カメラを起動中...";
const stream = await navigator.mediaDevices.getUserMedia({ video: true });
video.srcObject = stream;
// ビデオのデータが読み込まれたら、予測ループを開始します
video.addEventListener("loadeddata", predictWebcam);
}
}
// 毎フレーム実行される、映像の解析と描画を行うメインループ
async function predictWebcam() {
if (!webcamRunning) return; // カメラが停止していたら処理を中断
// 骨格を描画するキャンバスのサイズを、カメラ映像の実際のサイズに合わせます
canvasElement.width = video.videoWidth;
canvasElement.height = video.videoHeight;
// 現在のビデオフレームをAIモデルに渡して、ジェスチャーを認識させます
const results = gestureRecognizer.recognizeForVideo(video, Date.now());
// 前のフレームに描画した骨格などを消去します
canvasCtx.clearRect(0, 0, canvasElement.width, canvasElement.height);
// 「骨格を表示」がオンの場合、検出した手の骨格を描画します
if (skeletonCheckbox.checked && results.landmarks) {
// 描画設定を一時的に保存します(この中の変形処理が他の描画に影響しないようにするため)
canvasCtx.save();
// CSSで映像を左右反転させているため、骨格の描画も同じように反転させます
canvasCtx.scale(-1, 1);
canvasCtx.translate(-canvasElement.width, 0);
// 検出された全ての手の骨格を描画します
for (const landmarks of results.landmarks) {
drawingUtils.drawConnectors(landmarks, GestureRecognizer.HAND_CONNECTIONS, { color: "#FFFFFF", lineWidth: 5 });
drawingUtils.drawLandmarks(landmarks, { color: "#007bff", lineWidth: 2 });
}
// 描画設定を元に戻します
canvasCtx.restore();
}
// ジェスチャーが認識されていれば、その名前と信頼度を表示します
if (results.gestures.length > 0) {
const categoryName = results.gestures[0][0].categoryName;
const score = parseFloat(results.gestures[0][0].score * 100).toFixed(2);
outputDiv.innerText = `ジェスチャー: ${categoryName} (${score}%)`;
} else {
outputDiv.innerText = "ジェスチャーなし";
}
// ブラウザの描画タイミングに合わせて、この関数を繰り返し呼び出します
window.requestAnimationFrame(predictWebcam);
}
// ボタンにクリックイベントを登録します
cameraButton.addEventListener("click", toggleWebcam);
</script>
</body>
</html>
✅ ポイント
- CDNでMediaPipeのモデルを読み込むだけでOK
- カメラの映像に骨格を描画する処理も含まれています
- ボタンを押すとカメラが起動し、手のジェスチャーを自動で認識
Geminiへの指示例
このQiita記事のURLをGeminiに渡して、こんなふうに頼んでみてください:
📝 指示例:
(上記のソースコードを貼り付けて)この記事のコードをベースに、ピースサイン(Victory)を認識したら、画面に紙吹雪が舞うアニメーションを追加してください。
この方法なら、環境の違いで動かないなんて心配もなし。AIとの共同作業がぐっとスムーズになります。
MediaPipeでできること(ほんの一部)
MediaPipeは、Googleが提供するAIビジョンライブラリです。ブラウザでも動くのが最大の特徴。
例えば、こんなことができます:
- 手のジェスチャー認識(今回使用)
- 顔検出・表情認識
- ポーズ検出(全身の骨格推定)
- 物体検出・トラッキング
- 顔のメッシュ(ARエフェクトなどに活用)
アイデア次第で、ゲーム、UI操作、教育アプリなど幅広く活用できます!
おわりに
GeminiのCanvas × MediaPipeの組み合わせは、「見えるAI体験」 をすぐに試せる最高の組み合わせです。
この記事のコードをベースに、あなたのアイデアで次の一歩を作ってみてください!