Teachable Machineで『右も左もわからない』を解消する

## 右も左もわからない

とはよく言ったもので、うちの子、「みぎ」 と 「ひだり」 が怪しい。
100%の確信持ってない。100どころか50も怪しい。

### わからないと困る
例えば道を歩いていて、「**車が来たから左に寄って！**」が通じない、なんなら右に行かれる可能性がある。
恐怖でしかない。早急に手を打たねばならない。

そこで、**Teachable Machine先生**に登場していただきました。

## できたやつ

https://docci.netlify.app/

https://twitter.com/mitoreterusuki/status/1665722880028549120

### 自主トレできる環境を作った

「右左の教え方」などというものは様々ありますが、やはり**楽しく学んでいただく**のが一番です。
親から「右はどっち？左は？」などと**プレッシャー**をかけられながらではなく、
**自分の動作**から答えが出てきたほうが楽しいんじゃないでしょうか。

## どう作るか

1. Teachable Machineの「**画像プロジェクト**」で、**みぎ、ひだり動作モデル**を作成する

2. 動作モデルをブラウザで読み込み、**推論〜判定できるWebアプリ**を作成する

3. **音を出して**結果をフィードバックする

4. 楽しんで **みぎ、ひだり** を習得できる


### 1.モデルを作る
#### 新規モデルの選択

Teachable Machineにアクセスし、「新しいプロジェクト」から「画像」 → 「標準の画像モデル」を選択します。

https://teachablemachine.withgoogle.com/

![Qiita-teachable-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480342/1774c6a4-780d-e468-ec7d-139b5647ce9c.png)
![Qiita-teachable-02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480342/55ff453a-f046-029b-6efb-bbcb2905bb09.png)


#### クラスの定義
左右の判定用に、「right」「left」のクラスを定義します。

![Qiita-teachable-03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480342/ce3101ab-b743-7815-8afa-d5628fc2533e.png)


クラスを追加して、動いていないじょうｔの判定用に「stay」、オマケ機能として「none」のクラスを定義します。


#### データの登録
「ウェブカメラ」→「長押しして録画」で学習データを作っていきます。

- right ： 右に動く
- left ： 左に動く
- stay ： 中央でじっとする
- none ： 画面から隠れる

できたら「トレーニング」を押して、モデルを作成します。
想定通りの動きになるまで、トライ＆エラーでがんばりましょう。

:::note info
撮影時の背景は単色、影の出ない環境が望ましいです。

:::

![Qiita-teachable-04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480342/50bda712-2c0e-a5b6-05eb-75b8a86de358.png)


### 2.Webアプリにする

<CodePen>

<p class="codepen" data-height="300" data-default-tab="result" data-slug-hash="zYmgabV" data-user="mitoreterusuki" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/mitoreterusuki/pen/zYmgabV">
  RaiseYourHand</a> by mitoreterusuki (<a href="https://codepen.io/mitoreterusuki">@mitoreterusuki</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>


<details><summary>JavaScript コード例</summary>

```JavaScript:script.js
// 作成したモデルのURL
const imageModelURL = '作成したモデルのURLを挿入';

// メインの関数（ここでは定義しているだけでボタンクリックされたら実行）
async function start() {
  // カメラからの映像ストリーム取得
  const stream = await navigator.mediaDevices.getUserMedia({
    audio: false,
    video: true,
  });
  
  // 「id="webcam"」となっているパーツ（videoタグ）を取得
  const video = document.getElementById('webcam');
  
  // videoにカメラ映像ストリームをセット
  video.srcObject = stream;
  
  // Googleのサーバーにアップロードした自作モデルを読み込みにいきます
  const classifier = ml5.imageClassifier(imageModelURL + 'model.json', video, () => {
    // 読み込みが完了次第ここが実行されます
    console.log('モデルの読み込みが完了しました');
  });
  
  // 音楽を再生する関数（右）
function playAudioRight() {
  var audio = new Audio("https://docci.netlify.app/right.mp3");
  audio.play();
}
  // 音楽を再生する関数（左）
function playAudioLeft() {
  var audio = new Audio("https://docci.netlify.app/left.mp3");
  audio.play();
}
  // 音楽を再生する関数（不在）
function playAudioNone() {
  var audio = new Audio("https://docci.netlify.app/inai.mp3");
  audio.play();
}

  
 // 繰り返し処理
function loop() {
  // 推論を実行し、エラーがあればerrに、結果をresultsに格納して、
  // 推論が完了次第 { } の中身を実行します
  classifier.classify(async (err, results) => {
    // 結果のresultsは配列ですが、先頭に中身があれば以下の処理を実行します
    if (results[0]) {
      console.log(results[0].label); // コンソール表示
      document.getElementById("result").textContent = results[0].label;
      
      // resultsが"left"の場合、左のMP3を再生します
      if (results[0].label === "left") {
        playAudioLeft();
      }
      // resultsが"right"の場合、右のMP3を再生します
      if (results[0].label === "right") {
        playAudioRight();
      }
      // resultsが"none"の場合、いないのMP3を再生します
      if (results[0].label === "none") {
        playAudioNone();
      }

    }
    // 推論終了3秒後に自分の関数を実行（ループになる）
    setTimeout(loop, 3000);
  });
}
  // 最初の繰り返し処理を実行
  loop();
}
```

</details>

script.js の冒頭部分で、作成したTeachable Machineのモデルを読み込んでいます。

```JavaScript:一部抜粋
// 作成したモデルのURL
const imageModelURL = 'https://teachablemachine.withgoogle.com/models/abc123/';
```

音声はaudioタグで指定し、モデルの判定結果に応じて再生する音声を変更します。

```JavaScript:一部抜粋
// resultsが"none"の場合、いないのMP3を再生します
  if (results[0].label === "none") {
    playAudioNone();
}

// 音楽を再生する関数（不在）
function playAudioNone() {
  var audio = new Audio("https://docci.netlify.app/inai.mp3");
  audio.play();
}
```

### 3.音声ファイルを作る

フリー素材のちょうどいい音声が見当たらなかったので、**GarageBand**で自作しました。
Windowsの方はGoogle先生に作り方を聞いてみてください。

https://support.apple.com/ja-jp/guide/garageband/gbnd7cbf5ed9/mac

https://kumak1.hatenablog.com/entry/2018/09/27/234203


### 4.アップロード

**Netlify**を使って、Webアプリとして公開しましょう。

https://qiita.com/niihara_megumu/items/db8c53f0f5de9f377976




## おわりに

身体の動き（**上体を左右に倒す、手を挙げる**）で判定できるモデルが望ましかったのですが
なかなか難しく、試行錯誤の結果「**デコラピカチュウ**」に助けてもらいました。

簡単そうで奥が深いTeachable Machine、ぜひお試しください！