ml5.jsのImage Classifierをブラウザでアップした画像に対して実行する

ブラウザ上で手軽に機械学習もでるを扱えるml5.jsを使って、ローカルからアップした画像を認識させるための手順。

##ソース

```HTML
<html>

<head>
  <meta charset="UTF-8">
  <title>画像をアップロードすると画像認識してくれるページ</title>
  <script src="https://unpkg.com/ml5@latest/dist/ml5.min.js"></script>
  <style></style>
</head>

<body>
  <h1>画像をアップロードすると画像認識してくれるページ</h1>
    <p id="label">label:</p>
    <p id="confidence">confidence:</p>
<div class="upload"><input type="file" name="file" id="file"></div>
<canvas id="canvas"></canvas>

  <script>
  let file = document.getElementById('file');
  let canvas = document.getElementById('canvas');
  let canvasWidth = 400;
  let canvasHeight = 300;
  let uploadImgSrc;
  let label = document.querySelector("#label");
  let confidence = document.querySelector("#confidence");

  // 作成したモデルのURL
  const imageModelURL = 'Teachable Machineで作成したモデルのURL';

  // Canvasの準備
  canvas.width = canvasWidth;
  canvas.height = canvasHeight;
  let ctx = canvas.getContext('2d');

  let classifier = ml5.imageClassifier(imageModelURL + 'model.json', () => {
      // ロード完了
      console.log('Model Loaded!');
    });

//画像を読み込む関数
  function loadLocalImage(e) {
    // ファイル情報を取得
    let fileData = e.target.files[0];

    // 画像ファイル以外は処理を止める
    if (!fileData.type.match('image.*')) {
      alert('画像を選択してください');
      return;
    }

    // FileReaderオブジェクトを使ってファイル読み込み
    let reader = new FileReader();
    // ファイル読み込みに成功したときの処理
    reader.onload = function () {
      // Canvas上に表示する
      uploadImgSrc = reader.result;
      canvasDraw();
    }
    // ファイル読み込みを実行
    reader.readAsDataURL(fileData);
  }

  // ファイルが指定された時にloadLocalImage()を実行
  file.addEventListener('change', loadLocalImage, false);

  // Canvas上に画像を表示する関数
  function canvasDraw() {
    // canvas内の要素をクリアする
    ctx.clearRect(0, 0, canvasWidth, canvasHeight);

    // Canvas上に画像を表示
    let img = new Image();
    img.src = uploadImgSrc;
    img.onload = function () {
     if (this.width / this.height > canvasWidth / canvasHeight) {
        // 幅に合わせて画像サイズ設定
        var imgWidth = canvasWidth;
        var imgHeight = Math.floor(this.height * (canvasWidth / this.width));
      } else {
        // 高さに合わせて画像サイズ設定
        imgHeight = canvasHeight;
        imgWidth = Math.floor(this.width * (canvasHeight / this.height));
      }

      ctx.drawImage(img, 0, 0, imgWidth, imgHeight);
    }
    classifyCanvas();
  }

  function classifyCanvas() {
    classifier.classify(canvas, gotResult);
  }

  // 画像認識結果を表示する関数
  function gotResult(error, results) {
    if (error) {
      console.error(error);
    }
    console.log(results);
    // 結果のラベルと信頼度を表示
    label.textContent = `Label: ${results[0].label}`;
    confidence.textContent = `Confidence: ${results[0].confidence.toFixed(4)}`;
  }
  </script>
</body>

</html>

```

##モデルの準備
モデルのURLを指定してコールバック関数を呼び出すだけです。

```JavaScript
// 作成したモデルのURL
const imageModelURL = 'Teachable Machineで作成したモデルのURL';
let classifier = ml5.imageClassifier(imageModelURL + 'model.json', () => {
    // ロード完了
    console.log('Model Loaded!');
});
```

##イメージのアップロード
HTML要素としてinputをtype="file"で利用

```HTML
<input type="file" name="file" id="file">
```

アップロード処理は以下の部分

```JavaScript
  function loadLocalImage(e) {
    // ファイル情報を取得
    let fileData = e.target.files[0];

    // 画像ファイル以外は処理を止める
    if (!fileData.type.match('image.*')) {
      alert('画像を選択してください');
      return;
    }

    // FileReaderオブジェクトを使ってファイル読み込み
    let reader = new FileReader();
    // ファイル読み込みに成功したときの処理
    reader.onload = function () {
      // Canvas上に表示する
      uploadImgSrc = reader.result;
      canvasDraw();
    }
    // ファイル読み込みを実行
    reader.readAsDataURL(fileData);
  }

  // ファイルが指定された時にloadLocalImage()を実行
  file.addEventListener('change', loadLocalImage, false);
```

##Canvasへの描画
画像ファイルを読み込むと以下の関数が実行される

```JavaScript
  function canvasDraw() {
    // canvas内の要素をクリアする
    ctx.clearRect(0, 0, canvasWidth, canvasHeight);

    // Canvas上に画像を表示
    let img = new Image();
    img.src = uploadImgSrc;
    img.onload = function () {
     if (this.width / this.height > canvasWidth / canvasHeight) {
        // 幅に合わせて画像サイズ設定
        var imgWidth = canvasWidth;
        var imgHeight = Math.floor(this.height * (canvasWidth / this.width));
      } else {
        // 高さに合わせて画像サイズ設定
        imgHeight = canvasHeight;
        imgWidth = Math.floor(this.width * (canvasHeight / this.height));
      }

      ctx.drawImage(img, 0, 0, imgWidth, imgHeight);
    }
    classifyCanvas();
  }
```

最初に宣言したcanvasのサイズ（今回は横400,縦300）に画像側をリサイズして描画している。

##画像認識処理の実行
先ほどの描画関数の最後でclassifyCanvas()を呼んでいる。
認識処理完了したらコールバック関数で結果を画面表示。

```JavaScript
  function classifyCanvas() {
    classifier.classify(canvas, gotResult);
  }

  // 画像認識結果を表示する関数
  function gotResult(error, results) {
    if (error) {
      console.error(error);
    }
    console.log(results);
    // 結果のラベルと信頼度を表示
    label.textContent = `Label: ${results[0].label}`;
    confidence.textContent = `Confidence: ${results[0].confidence.toFixed(4)}`;
  }
```