保育園児の折り紙あるある「これ折って！」に応える機械学習型WEBアプリを初心者がプロトタイピング

保育園で作った**謎の折り紙**を嬉しそうに持って帰ってくるうちの保育園児。
**　子：「先生にこれ作ってもらった！もう一つ作って！」**
**　父：「え、、、」（なにこれ、、、飛行機か？）**
**　子：「早く早く！」**
**　父：「お、おう、、」（どうしよう。。）**

このようなシチュエーションありますよね？！
折しも、機械学習とやらに挑戦しているところなので、この身近な「**保育園児あるある**」を**機械学習の技術を使って解決**してみたいとおもいます。というわけで以下の通りプロトタイピングしてみました。題して「とうちゃんこれ折って！」これがあれば、父ちゃんの威厳を保てます！

##動作の様子
機能の説明が難しいので、まずはプロトタイプの動画をご覧いただきイメージアップください。
<iframe width="560" height="315" src="https://www.youtube.com/embed/CLU-D7ZXgyA" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

##機能概要

* 子供が保育園で作ってきた折り紙（作品）をスマホのカメラで撮影すると以下の情報を提供するWEBアプリです。
    * 折り紙の作品名（鶴とか蝉とか、メダルとか）
    * 作り方説明動画
* さらに**ここが素敵！**（自画自賛）
    * 途中で作り方が分からなくなったら、その時点の折り紙をスマホのカメラで撮影。なんと、そこからの手順を動画で解説！**楽々リスタート！**
    * 作品にまつわる現実の画像を表示！「本物はこんななんだね！」と**子供と盛り上がる**こと間違いなし！


##機能構成
Teachable Machineで**折り紙の形**を機械**学習**し、カメラで撮影した「作品」および「作品の制作過程」を判定できるようにします。
判定結果に応じ「作成手順を説明した**動画**」**を再生**します。作品に応じた**実世界の画像**をPixabayから取得して**表示**します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/365273/b76c3824-3c51-e992-b4a9-e36eded204ae.png)

##準備するもの

###折り紙の形を機械学習したモデル
GoogleのTeachable Machineを利用しました。
こちら様のドキュメントを参考にさせていただきました。

https://qiita.com/Gerbera/items/165a4d026cf4999ef5b2

Teachable Machineを用いたトレーニングのイメージ
<font color="red">**ブラウザとカメラだけ**</font>で簡単にトレーニングができます。**コーディングなどしません**。この**手軽さ**は本当に**驚き**です。
**とても簡単かつ面白い**ので、ぜひチャレンジしていただくことをおススメいたします！
<IMG Width = "600" SRC="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/365273/f00b071d-7601-1f66-78f8-a2665be1284f.png">
今回は、うちの保育園ではおなじみの「蝉」と「メダル」の折り紙を学習させました。実際に使えるアプリケーションにするためには、もっと**たくさんの種類の「折り紙」を学習させる**必要があります。


###折り紙手順が分かる動画（最初から最後まで、途中から最後まで）
最初から完成までの作成手順を記録した動画に加えて、途中からリスタートする場合の動画を作成（切り出し）します。
**機械学習させたクラスと相対するよう動画を準備**します。
なかなか面倒です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/365273/7bffb652-bda3-c70c-ad70-29d766f1aa2e.png)

###プログラム
以下のライブラリを利用して、Javascriptで開発しました。

* 利用したライブラリ vue.js および ml5.js
* 利用したWEBAPI Pixabay Developer API

Pixabayについては、こちら様のドキュメントを参考にさせていただきました。

https://paiza.hatenablog.com/entry/2017/11/30/120%E4%B8%87%E6%9E%9A%E8%B6%85%E3%81%88%E3%81%AE%E7%94%BB%E5%83%8F%E3%82%92JavaScript%E3%81%8B%E3%82%89%E7%84%A1%E6%96%99%E3%81%A7%E4%BD%BF%E3%81%88%E3%82%8B%E3%80%8CPixabay_API%E3%80%8D%E3%81%A7%E7%94%BB

作成したプログラムについては以下のセクションを参照ください
<details><summary>サンプルプログラム</summary><div>

```HTML:index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>これ折っちゃおう！</title>
  </head>

  <body>
    <h1>折り紙を折ろう！</h1>
    <div id="app">
        <p>処理状況：{{ modelState }}</p>
        <p>この折り紙は：{{ detectedName }}ですね</p>
        <button v-on:click="modelhantei">折り紙の写真を撮る</button><BR>
        <video id="myvideo" width="320" height="240" muted autoplay playsinline></video>
        <br />
          <h2>作り方！</h2>
	    <video id="videoplay" width="320" height="240" ></video>
        <br />        
          いろいろ見てみよう！<BR>
      <button v-on:click="getsamplepic">サンプル画像取得</button><BR>
      <div id = "result"></div>
    </div>
    
    <!-- ml5.jsとVue.jsをCDNから読み込みます -->
    <script src="https://unpkg.com/ml5@latest/dist/ml5.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>

      // 作成したモデルのURL
      const imageModelURL = 'https://teachablemachine.withgoogle.com/models/hc5kqu-hB/';
      let classifier;

      const app = new Vue({
        el: '#app',
        data: {
          modelState: '準備しています。ちょっとまってね・・・',
          detectedName: '',

          
        },
        async mounted() {
            // デバイス（カメラ・マイク）からのデータ取得を試みる
            // 映像や音声が使えるデバイスが確定するまで時間がかかるためawaitを使う
            const devices = await navigator.mediaDevices.enumerateDevices();
            console.log(devices);
            // カメラからの映像取得   //私のスマホの背面カメラは1番
            const stream = await navigator.mediaDevices.getUserMedia({
                audio: true,
                video: { deviceId: devices[1].deviceId },
            });


          // IDが"myvideo"であるDOMを取得
          const video = document.getElementById('myvideo');

          // videoにカメラ映像をセット
          video.srcObject = stream;

          // 自作モデルのロード
          classifier = ml5.imageClassifier(imageModelURL + 'model.json', video, () => {
            // ロード完了
            app.modelState = '折り紙モデルのロードが完了しました。';
            console.log('Model Loaded!');
          });
        },

        methods: {
          modelhantei: function () {
            classifier.classify((err, results) => {
              console.log(results);
              if (results[0]) {
                let res = '';
                res = results[0].label;
                if (res == 'semi'){
                  app.detectedName = '蝉';　//Debug・Demo用

                }

                 
                    //判定した結果を受けてセミの作り方動画を再生　＊＊ここはモデル名とファイル名を同じにしておく。＊＊
                    vp = document.getElementById("videoplay");
                    vp.src = "./" + res + ".mp4";
                    vp.play();
                  
              } else {
                app.detectedName = 'わからない...';
              }
            });
          },

          getsamplepic:function(){   
            //画像を取得するためのURLを生成する
            let URL = this.createURL(app.detectedName);
            console.log(URL);

            
            fetch( URL )
            .then( function( data ) {
              return data.json();  //JSONデータとして取得する
            })
            .then( function( json ) {
              console.log(json);    

              //直書きする/////////////////
              let result = document.getElementById('result');
              result.innerHTML = '';  //検索するごとに画面をリセットする
                          //該当する画像があれば
              if( json.totalHits > 0 ) {
                json.hits.forEach( function( value ) {
                let img = document.createElement('img');
                let a = document.createElement('a');

                a.href = value.pageURL;  //ダウンロード用のサイトURL
                a.target = '_blank';
                img.src = value.previewURL;  //プレビュー用の画像URL
                
                a.appendChild( img );
                result.appendChild( a );
                })
              }
              else {
                alert('該当する写真がありません');
              }
            })
            

          },

          //リクエスト用のURLを生成する
          createURL:function( value ) {
            let API_KEY = '*****取得したAPI KEY*****';
            let baseUrl = 'https://pixabay.com/api/?key=' + API_KEY;
            let keyword = '&q=' + encodeURIComponent( value );
            let option = '&orientation=horizontal&per_page=3';
            let URL = baseUrl + keyword + option;
            
            return URL;
            
          },


        },

      });
    </script>
  </body>
</html>
```
</div></details>


##今後に向けて
今回はプロトタイプということで、学習した折り紙は「蝉」と「メダル」の2種類のみ。途中からリスタートするためのクラスも「蝉」の一部のみとしました。使い物になるアプリケーションとするためには、折り紙のバリエーションを増やす必要があります。また、途中からリスタートするための説明動画を複数準備しましたがこれもなかなか面倒な作業です。この点については、**動画の中身を解析してくれるAI**（GoogleのCloud Video Intelligence API）というものがあるようなので、それを使うことで、最初から完成までの動画一つで、どこからでもリスタートできるようになりそうです。機械学習ってすごいですね！そんなわけで、次はGoogleのソレを使ってみたいなと思います。

https://cloud.google.com/video-intelligence/