kintone と Teachable Machine で画像認識してみた

今回はkintone上でTeachableMachineを使ってかんたんな画像認識してみたいと思います。

# Teachable Machineの準備をする

↓こちらにアクセスして
https://teachablemachine.withgoogle.com/

使ってみるをクリック！
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536148/15e3c847-68be-0f96-8486-1624a618d2a9.png" width="300px">

画像プロジェクトを選択し、標準の画像モデルを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536148/7aede037-f630-e263-ae77-6343c76feeb5.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536148/304d5767-61fa-8e97-9f62-4e6d07f83fc6.png)

## クラス名を変更する

Class 1 を「ケーキ」に
Class 2 を「コップ」に

書き換えます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536148/d6d6ac51-92fd-40e5-688b-aa42227eb9b4.png)

## 画像をアップロードする。

私がフリーハンドで描いたケーキの絵と、コップの絵をそれぞれケーキクラス、コップクラスにアップロードします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536148/7bdd0aa5-fd7b-df38-ac70-0291b4c02294.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536148/14db5a7c-a986-cfca-af03-7a380b7f2ba6.png)


| クラス | 画像 |
|:-:|:-:|
| ケーキ  |<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536148/a784f335-a105-476e-af33-5985a4bf61a8.png" width="150px">　　<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536148/5cf46b7c-60b9-7700-0e82-f51b66526525.png" width="150px"><br><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536148/e3ee9405-8b06-acdd-d333-2957702d56d8.png" width="150px">　　<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536148/c46045fb-b20b-d0c4-8dd0-049e849bc8dd.png" width="150px"> |
| コップ  | <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536148/3d917151-e9ac-a562-98d6-73180629e286.png" width="150px">　　<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536148/6c8250d1-fc54-1faf-ecb0-4f8bad04dcbf.png" width="150px"><br><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536148/9f9a8f53-b898-69be-d345-c8972c653fcf.png" width="150px">　　<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536148/d268d864-8ce3-81bd-5d5f-911ba0079843.png" width="150px">  |


↓読み込んだらこんな感じになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536148/0571a893-a9e2-7e3f-44b5-14bd3c24868a.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536148/682e0047-9c4a-9d21-2582-bfb05429a9c9.png)

## トレーニング

モデルをトレーニングするボタンを押します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536148/3a96fb8b-232f-f7cd-20a1-cda55359fb00.png)

## モデルをエクスポート→アップロードする

モデルをエクスポートボタンをクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536148/9abca362-7af4-68ba-5d7f-e161eb7ab227.png)

モデルをアップロードします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536148/d427e1af-d411-3b06-4e9a-a9bd6d475f2f.png)

暫く待つと、クラウドモデルは最新です。と表示される＆「共有可能なリンク」が表示されるのでコピーしておきます。
ちゃんと控えておきましょう！！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536148/72bc15d4-5409-c119-00b3-f675a7cf6fa9.png)

# kintoneアプリの作成

フォームは作成しなくていいので「一覧」を作成します。
一覧はカスタマイズビューにして、htmlに次のように書きます。

```html
<div>Teachable Machine Image Model</div>
<div id="webcam-container"></div>
<div id="label-container"></div>
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536148/e3f3c19e-4191-6fb1-7d73-b4a78eae6a66.png)

## JavaScript / CSSでカスタマイズ

「JavaScript / CSSでカスタマイズ」に下記2つを追加しておきます。
`https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@1.3.1/dist/tf.min.js`
`https://cdn.jsdelivr.net/npm/@teachablemachine/image@0.8/dist/teachablemachine-image.min.js`

また、kintone UI Comnponentも追加しておきましょう。

コード本体には（ほぼコピペですが）次のように書きます。
const URL=""内に、先程コピーした共有可能なリンクを貼り付けます。

```js
(() => {
  // レコード追加画面表示時
  kintone.events.on(["app.record.index.show"], function (event) {
    // the link to your model provided by Teachable Machine export panel
    const URL = "【コピーした共有可能なリンク】";

    let model, webcam, labelContainer, maxPredictions;
    // メニュー下の余白
    const sp = kintone.app.getHeaderSpaceElement();
    const btn = new Kuc.Button({
      text: "ボタン",
      type: "submit",
    });
    sp?.appendChild(btn);

    btn.addEventListener("click", async () => {
      const modelURL = URL + "model.json";
      const metadataURL = URL + "metadata.json";

      // load the model and metadata
      // Refer to tmImage.loadFromFiles() in the API to support files from a file picker
      // or files from your local hard drive
      // Note: the pose library adds "tmImage" object to your window (window.tmImage)
      model = await tmImage.load(modelURL, metadataURL);
      maxPredictions = model.getTotalClasses();

      // Convenience function to setup a webcam
      const flip = true; // whether to flip the webcam
      webcam = new tmImage.Webcam(200, 200, flip); // width, height, flip
      await webcam.setup(); // request access to the webcam
      await webcam.play();
      window.requestAnimationFrame(loop);

      // append elements to the DOM
      document.getElementById("webcam-container").appendChild(webcam.canvas);
      labelContainer = document.getElementById("label-container");
      for (let i = 0; i < maxPredictions; i++) {
        // and class labels
        labelContainer.appendChild(document.createElement("div"));
      }
    });

    async function loop() {
      webcam.update(); // update the webcam frame
      await predict();
      window.requestAnimationFrame(loop);
    }

    // run the webcam image through the image model
    async function predict() {
      // predict can take in an image, video or canvas html element
      const prediction = await model.predict(webcam.canvas);
      for (let i = 0; i < maxPredictions; i++) {
        const classPrediction =
          prediction[i].className + ": " + prediction[i].probability.toFixed(2);
        labelContainer.childNodes[i].innerHTML = classPrediction;
        console.log(prediction);
      }
    }
    return event;
  });
})();

```

# まとめ

アプリを開いて「ボタン」をクリックするとカメラが起動し、カメラに映る物が「コップ」か「ケーキ」か見分けてくれます。
（PCのカメラにスマホでいらすとやのイラストを見せてみました）

| ケーキ | コップ |
|:-:|:-:|
| <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536148/69a48b19-6213-ad91-efe0-efba3cb18e4b.png" width="300px"><br>ケーキの可能性が濃厚！  | <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536148/eec6b5cb-f7fc-f24a-dbe5-b4ef19bd30e2.png" width="300px"><br>コップの可能性が濃厚！ |