Teachable Machineでグー・チョキ・パーを判定するAIシステムを作ってみた|新人エンジニア向けに仕組みをやさしく解説
https://saycon.co.jp/yuu/tmic.html
こんにちは。ゆうせいです。
今回は、Teachable Machineを使って「グー・チョキ・パー」をWebカメラで判定するAIシステムを作成した、という内容を新人エンジニア向けに解説します。
完成したシステムでは、ブラウザでカメラを起動し、手の形を映すだけで、AIが「グー」「チョキ」「パー」のどれに近いかをリアルタイムに判定します。
じゃんけんの手をAIが見分けると聞くと、少し難しそうに感じますよね。
でも、仕組みを分解すると、次のような流れです。
手の画像を集める
↓
Teachable Machineで学習する
↓
学習済みモデルを公開する
↓
Webページからモデルを読み込む
↓
カメラ映像をAIに渡す
↓
グー・チョキ・パーの判定結果を表示する
日本語で言えば、あらかじめAIにグー・チョキ・パーの画像を学習させておき、ブラウザ上でカメラ映像を読み取って、最も近い手の形を判定する流れです。
Teachable Machineとは何か
Teachable Machineとは、Googleが提供している機械学習モデル作成ツールです。
専門的なプログラミングをたくさん書かなくても、画像、音声、姿勢などを分類するAIモデルを作成できます。
機械学習とは、コンピューターに大量の例を見せて、パターンを学ばせる技術です。
今回なら、AIに次のような例を見せます。
| 分類名 | AIに見せる画像の例 | AIが学ぶこと |
|---|---|---|
| グー | 握った手の画像 | 指が閉じている形 |
| チョキ | 2本指を出した画像 | 人差し指と中指が伸びている形 |
| パー | 手を開いた画像 | 指が広がっている形 |
たとえるなら、先生が生徒に「この写真はグー」「この写真はチョキ」「この写真はパー」と何度も見せて、見分け方を覚えさせるようなものです。
AIは、人間のように「じゃんけんの意味」を理解しているわけではありません。
画像の中にある色、形、輪郭、明るさなどのパターンから、どの分類に近いかを判断しています。
今回作成したシステムの概要
今回のシステムは、HTML、CSS、JavaScriptで作成したWebアプリです。
ブラウザでページを開き、カメラの使用を許可すると、学習済みのTeachable Machineモデルが映像を読み取り、画面下部に判定結果と信頼度を表示します。
信頼度とは、AIがその判定にどれくらい自信を持っているかを示す数値です。
たとえば、画面に「グー(92.5%)」と表示された場合、AIは現在の映像をグーとしてかなり強く判定している、という意味になります。
| 項目 | 内容 |
|---|---|
| 目的 | Webカメラ映像からグー・チョキ・パーを判定する |
| 使用技術 | HTML、CSS、JavaScript、p5.js、ml5.js、Teachable Machine |
| 入力 | Webカメラの映像 |
| 出力 | 分類ラベルと信頼度 |
| 実行環境 | HTTPS環境またはlocalhostのブラウザ |
なぜp5.jsとml5.jsを使うのか
今回のコードでは、p5.jsとml5.jsというJavaScriptライブラリを使っています。
ライブラリとは、よく使う機能をまとめた道具箱のようなものです。
自分で全部の処理を書く代わりに、便利な部品を借りて開発できます。
| ライブラリ | 役割 | たとえ |
|---|---|---|
| p5.js | カメラ映像やキャンバス表示を扱いやすくする | 画用紙とカメラ係 |
| ml5.js | 機械学習モデルをJavaScriptから扱いやすくする | AIモデルとの通訳係 |
p5.jsは、ブラウザ上に映像や図形を表示するために使います。
今回のシステムでは、Webカメラの映像をキャンバスに表示する役割を持っています。
キャンバスとは、ブラウザ上で画像や図形を描画するための領域です。
ml5.jsは、Teachable Machineで作成した画像分類モデルを読み込み、カメラ映像をAIに判定させるために使います。
新人エンジニア向けに言えば、p5.jsが「画面表示担当」、ml5.jsが「AI判定担当」です。
コード全体の構成
今回のWebアプリは、大きく3つの部分で構成されています。
| 部分 | 役割 |
|---|---|
| HTML | 画面の構造を作る |
| CSS | 見た目を整える |
| JavaScript | カメラ起動、AIモデル読み込み、画像判定を行う |
HTMLは、家でいう骨組みです。
CSSは、壁紙や家具の配置です。
JavaScriptは、電気や水道のように、画面に動きを与える仕組みです。
Webアプリを作るときは、この3つの役割を分けて考えると理解しやすくなります。
学習済みモデルを読み込む部分
今回のシステムでは、Teachable Machineで作成した学習済みモデルを、次のURLから読み込んでいます。
const imageModelURL = "https://teachablemachine.withgoogle.com/models/qMF2QlY9-/";
このURLは、Teachable Machineで作成したモデルの置き場所です。
モデルとは、AIが学習した結果のことです。
グー、チョキ、パーの画像を学習した結果が、このURLの先に保存されています。
コードでは、さらにmodel.jsonを付けて読み込んでいます。
classifier = ml5.imageClassifier( imageModelURL + "model.json", modelLoaded );
imageClassifierとは、画像分類を行うための機能です。
画像分類とは、画像を見て「どのクラスに属するか」を判定する処理です。
今回なら、映像の1コマを見て「グー」「チョキ」「パー」のどれに近いかを判定します。
preload関数の役割
p5.jsでは、preloadという関数が使えます。
preloadは、画像やモデルなど、事前に読み込んでおきたいものを準備する場所です。
function preload() {
classifier = ml5.imageClassifier(
imageModelURL + "model.json",
modelLoaded
);
}
日本語で言えば、画面を動かし始める前に、AIモデルを先に読み込んでおく処理です。
料理でたとえるなら、調理を始める前に材料を冷蔵庫から出しておくようなものです。
材料がないまま料理を始めると困りますよね。
AI判定も同じで、モデルを読み込まないと分類できません。
モデル読み込み完了を管理する
モデルの読み込みが完了すると、modelLoaded関数が呼ばれます。
function modelLoaded() {
modelReady = true;
setStatus("AIモデルを読み込みました。カメラを準備しています。");
startClassificationWhenReady();
}
modelReadyという変数は、AIモデルの準備が終わったかどうかを管理しています。
このように状態を管理する変数を使うと、処理の流れが分かりやすくなります。
今回のシステムでは、AIモデルの準備とカメラの準備が両方終わってから分類を始めます。
片方だけ準備できても、まだ判定はできません。
たとえるなら、野球の試合で、選手は来たけれどグラウンドが使えない状態では試合が始められない、という感じです。
カメラを起動するsetup関数
p5.jsでは、setup関数が最初に1回だけ実行されます。
今回のsetup関数では、キャンバスを作成し、Webカメラを起動しています。
function setup() {
const canvas = createCanvas(320, 260);
canvas.parent("canvas-container");
video = createCapture(
{
video: {
facingMode: "user",
width: { ideal: 320 },
height: { ideal: 240 }
},
audio: false
},
() => {
cameraReady = true;
setStatus("カメラを認識しました。分類を開始します。", "success");
startClassificationWhenReady();
}
);
video.size(320, 240);
video.hide();
textFont("sans-serif");
}
createCanvasは、画面に映像や文字を描くためのキャンバスを作る関数です。
createCaptureは、Webカメラの映像を取得する関数です。
facingModeにuserを指定しているため、スマートフォンやPCでは基本的に自分側のカメラを使います。
audioはfalseになっています。
つまり、音声は使わず、映像だけを取得します。
分類開始のタイミングを制御する
今回のコードで良いポイントは、AIモデルとカメラの両方が準備できてから分類を始めている点です。
function startClassificationWhenReady() {
if (
modelReady &&
cameraReady &&
!classificationStarted
) {
classificationStarted = true;
classifyVideo();
}
}
この条件分岐では、次の3つを確認しています。
| 条件 | 意味 |
|---|---|
| modelReady | AIモデルの読み込みが完了している |
| cameraReady | カメラの準備が完了している |
| !classificationStarted | 分類処理がまだ開始されていない |
このように条件を明確にしておくと、モデルが読み込まれる前に判定しようとしてエラーになる、といった問題を防ぎやすくなります。
新人エンジニアは、非同期処理に慣れておきましょう。
非同期処理とは、処理の完了タイミングがすぐには決まらない処理のことです。
モデル読み込みやカメラ起動は、環境によって完了までの時間が変わります。
だから、「準備できたら開始する」という考え方が大切です。
カメラ映像を画面に表示するdraw関数
p5.jsのdraw関数は、繰り返し実行されます。
今回のdraw関数では、カメラ映像を表示し、その下に判定結果を表示しています。
function draw() {
background(0);
if (video) {
push();
translate(width, 0);
scale(-1, 1);
image(video, 0, 0, width, 240);
pop();
}
fill(255);
noStroke();
textSize(16);
textAlign(CENTER, CENTER);
const confidenceText =
confidence > 0 ? `(${(confidence * 100).toFixed(1)}%)` : "";
text(
`${label}${confidenceText}`,
width / 2,
250
);
}
ここで注目したいのは、映像を左右反転している部分です。
translate(width, 0); scale(-1, 1);
Webカメラの映像は、そのままだと鏡のように見えない場合があります。
じゃんけんの手をカメラに映すとき、画面上の動きが自分の感覚と逆になると少し操作しづらいですよね。
そこで、映像を左右反転して、鏡のように自然に見えるようにしています。
ユーザーの使いやすさまで考えている点が大切です。
AIに映像を判定させる処理
実際にAIへ映像を渡して判定させる処理が、classifyVideo関数です。
function classifyVideo() {
if (!classificationStarted || !video) return;
flippedVideo = ml5.flipImage(video);
classifier.classify(flippedVideo, gotResult);
}
ml5.flipImageは、映像を反転させるための処理です。
classifier.classifyは、画像分類モデルに映像を渡して、分類結果を取得する処理です。
判定が終わると、gotResult関数が呼ばれます。
このように、処理が終わった後に呼ばれる関数をコールバック関数と呼びます。
コールバック関数とは、「処理が終わったら、この関数を実行してね」と予約しておく関数です。
レストランで番号札をもらい、料理ができたら呼ばれるイメージに近いです。
判定結果を受け取るgotResult関数
gotResult関数では、AIの判定結果を受け取ります。
function gotResult(error, results) {
if (flippedVideo) {
flippedVideo.remove();
flippedVideo = null;
}
if (error) {
console.error(error);
label = "判定エラー";
confidence = 0;
setStatus(
"画像の判定中にエラーが発生しました。ページを再読み込みしてください。",
"error"
);
classificationStarted = false;
return;
}
if (results && results.length > 0) {
label = results[0].label;
confidence = results[0].confidence || 0;
}
classifyVideo();
}
resultsには、AIの分類結果が入っています。
多くの場合、最も可能性が高い判定結果がresults[0]に入ります。
labelには分類名が入ります。
confidenceには信頼度が入ります。
最後にclassifyVideoをもう一度呼ぶことで、次の映像フレームを再び判定します。
この繰り返しによって、リアルタイム判定が実現されています。
つまり、1回だけ判定して終わりではありません。
カメラ映像を見続けながら、何度も何度もAIに判定させています。
リアルタイム判定の流れ
今回のシステムのリアルタイム判定は、次のように動いています。
カメラ映像を取得
↓
映像を反転
↓
AIモデルへ渡す
↓
グー・チョキ・パーを判定
↓
ラベルと信頼度を更新
↓
次の映像を再び判定
日本語で言えば、カメラの現在映像をAIに渡し、判定結果を表示し、すぐ次の映像でも同じ処理を繰り返しているということです。
リアルタイムAI判定は、難しそうに見えます。
でも実際には、「入力」「判定」「表示」「繰り返し」という流れです。
まず流れをつかめ。
細かいコードはその後で読めば大丈夫です!
ステータス表示があると使いやすい
今回のコードでは、画面にステータスを表示しています。
AIモデルを読み込んでいます。 AIモデルを読み込みました。カメラを準備しています。 カメラを認識しました。分類を開始します。 画像の判定中にエラーが発生しました。
このようなメッセージは、ユーザーにとって非常に重要です。
画面が止まっているように見えても、「モデルを読み込んでいます」と表示されていれば、待てばよいと分かります。
エラーが起きたときも、何が問題なのかを伝えられます。
新人エンジニアは、機能だけでなく、利用者の不安を減らす表示も意識しましょう。
良いシステムは、動くだけではありません。
今何が起きているかを、利用者に伝えます。
HTTPSまたはlocalhostが必要な理由
Webカメラをブラウザから使う場合、基本的にHTTPS環境またはlocalhostが必要です。
HTTPSとは、通信を暗号化して安全にやり取りする仕組みです。
localhostとは、自分のPC上で動かしている開発用の環境です。
カメラはプライバシーに関わる機能です。
そのため、ブラウザは安全でない環境からカメラを勝手に使えないように制限しています。
たとえるなら、玄関の鍵です。
誰でも勝手に家に入れたら危険ですよね。
カメラも同じで、利用者の許可と安全な環境が必要です。
グー・チョキ・パー判定の精度を上げるコツ
AIの判定精度は、学習データの質に大きく左右されます。
うまく判定できない場合、コードだけでなく、Teachable Machineで学習させた画像も見直しましょう。
| 改善ポイント | 理由 |
|---|---|
| 明るい場所で撮影する | 手の形が見えやすくなる |
| 背景をできるだけシンプルにする | AIが背景ではなく手を見やすくなる |
| 手の位置を変えて撮影する | 中央以外でも判定しやすくなる |
| 左右の手や角度の違いも入れる | 現実の使い方に近づく |
| 各クラスの画像数をそろえる | 特定の分類に偏りにくくなる |
| 似た形を多めに学習する | グーと中途半端な手、チョキと指の開き具合などを区別しやすくなる |
AIは、学習していないものに弱いです。
たとえば、明るい部屋の画像だけで学習したAIは、暗い部屋で判定が不安定になることがあります。
学校のテストで、同じパターンの問題しか練習していないと、少し形が変わった問題で迷いますよね。
AIも同じです。
いろいろなパターンを見せてあげるほど、実際の利用場面に強くなります。
新人エンジニアが学べるポイント
このグー・チョキ・パー判定システムは、単なるおもちゃではありません。
新人エンジニアが学ぶべき要素がたくさん含まれています。
| 学べること | 内容 |
|---|---|
| 機械学習の基本 | 画像を学習させて分類する流れを体験できる |
| Webカメラの扱い | ブラウザから映像入力を取得する方法が分かる |
| JavaScriptの非同期処理 | モデル読み込みやカメラ起動の完了を待つ考え方が学べる |
| ライブラリ活用 | p5.jsやml5.jsを使って効率よく開発できる |
| UX設計 | ステータス表示やエラー表示の大切さが分かる |
| AIの限界 | 学習データや環境によって判定が変わることを理解できる |
UXとは、ユーザー体験のことです。
利用者がシステムを使ったときに、分かりやすいか、安心できるか、迷わないかを考える視点です。
AIシステムでは、精度だけでなく、使いやすさも大切です。
エラー処理も忘れてはいけない
今回のコードでは、エラーが起きたときの処理も書かれています。
if (error) {
console.error(error);
label = "判定エラー";
confidence = 0;
setStatus(
"画像の判定中にエラーが発生しました。ページを再読み込みしてください。",
"error"
);
classificationStarted = false;
return;
}
エラー処理とは、問題が起きたときにシステムがどう対応するかを決める処理です。
新人エンジニアは、正常に動く処理だけを書きがちです。
しかし、実際の開発では、失敗したときの動きがとても重要です。
モデルが読み込めない カメラが許可されない 通信が失敗する ブラウザが対応していない 判定処理でエラーが出る
このようなケースに備えておくと、利用者に親切なシステムになります。
成功時だけで満足するな。
失敗時の動きまで考えましょう!
このシステムを発展させるなら
グー・チョキ・パー判定ができたら、次はさまざまな発展が考えられます。
| 発展アイデア | 内容 |
|---|---|
| CPUと対戦するじゃんけんゲーム | AIが判定した手と、コンピューターの手で勝敗を決める |
| 判定履歴の表示 | 直近10回の判定結果を一覧にする |
| 信頼度が低い場合は再判定 | confidenceが一定未満なら「もう一度映してください」と表示する |
| 音声フィードバック | 判定結果を音声で読み上げる |
| 学習データを増やして精度改善 | 照明、背景、手の角度を増やして再学習する |
| スマートフォン対応の改善 | 画面サイズやカメラ向きを調整する |
特におすすめなのは、信頼度が低い場合の処理です。
たとえば、信頼度が60%未満なら、判定結果をそのまま表示せず、「手を中央に映してください」と表示します。
こうすると、AIの不確かな判定をそのまま使わずに済みます。
実務でも、AIの結果を100%信じるのではなく、信頼度や条件に応じて扱いを変える設計が重要です。
AIシステム開発で大切な考え方
今回のような画像分類システムを作るとき、新人エンジニアは次の考え方を持つとよいです。
| 考え方 | 説明 |
|---|---|
| AIは学習データに依存する | 良いデータを集めないと良い判定はできない |
| 判定には不確実性がある | 信頼度を見ながら扱う必要がある |
| 利用環境で精度が変わる | 照明、背景、カメラ品質によって結果が変わる |
| ユーザーへの説明が必要 | 読み込み中、判定中、エラー時の状態を伝える |
| 小さく作って改善する | 最初から完璧を狙わず、動くものを作って改善する |
AI開発は、普通のプログラム開発とは少し違います。
コードだけ直せば必ず改善するわけではありません。
学習データ、モデル、利用環境、UI、エラー処理をまとめて考える必要があります。
まるで料理の味を調整するようなものです。
レシピだけでなく、材料の質、火加減、盛り付け、食べる人の好みまで関係します。
まとめ
今回は、Teachable Machineを使ってグー・チョキ・パーを判定するAIシステムを作成した内容を、新人エンジニア向けに解説しました。
このシステムでは、Teachable Machineで学習した画像分類モデルを、ml5.jsでWebページに読み込み、p5.jsでカメラ映像を表示しながらリアルタイムに分類しています。
| 技術 | 役割 |
|---|---|
| Teachable Machine | グー・チョキ・パーを学習したAIモデルを作る |
| ml5.js | AIモデルをブラウザ上で扱う |
| p5.js | カメラ映像と判定結果を画面に描画する |
| JavaScript | モデル読み込み、カメラ起動、分類処理を制御する |
| HTML/CSS | 画面構造と見た目を整える |
全体の流れは、次の通りです。
Teachable Machineで学習
↓
モデルURLを取得
↓
Webページでモデルを読み込み
↓
Webカメラを起動
↓
映像をAIに渡す
↓
グー・チョキ・パーを分類
↓
ラベルと信頼度を表示
日本語で言えば、AIに手の形を学習させ、その学習済みモデルをWebページで利用し、カメラ映像から手の形を判定して画面に表示する流れです。
新人エンジニアにとって、この題材はとても良い学習テーマです。
なぜなら、機械学習、Webカメラ、JavaScript、非同期処理、UI設計、エラー処理を一度に体験できるからです。
今後の学習では、まずHTML、CSS、JavaScriptの基本を押さえましょう。その後、p5.jsでカメラ映像を扱い、ml5.jsで画像分類を試し、Teachable Machineで学習データを増やして精度改善に挑戦するとよいです。最初はグー・チョキ・パーで十分です。小さく作って、動かして、直す。この流れを繰り返して、AIアプリ開発に慣れていきましょう!
投稿者プロフィール

- 代表取締役
-
セイ・コンサルティング・グループ株式会社代表取締役。
岐阜県出身。
海外放浪の末、2000年創業、2004年会社設立。
IT企業向け人材育成研修歴業界歴20年以上。
すべての無駄を省いた費用対効果の高い「筋肉質」な研修を提供します!
この記事に間違い等ありましたらぜひお知らせください。
学生時代は趣味と実益を兼ねてリゾートバイトにいそしむ。長野県白馬村に始まり、志賀高原でのスキーインストラクター、沖縄石垣島、北海道トマム。高じてオーストラリアのゴールドコーストでツアーガイドなど。現在は野菜作りにはまっている。


