8_1_3 画像認識モバイルアプリ

TensorFlow.jsのmobilenetを使って、何の画像かを認識するモバイルアプリを作成します。これは、具体的に言うと、mobilenetが利用するMobileNetsのV1モデルに、モバイルデバイスがHTMLの<video>要素に映っている画像を認識させ、その分類結果を表示する、というアプリです。

また、分類結果は英語で返ってくるので、Google Apps Scriptを使って日本語へ翻訳し、それを確率とともに表示するようにします。

HTMLは次のコードです。<canvas>要素にはstyle=”display:none”を設定し、画面で見えなくしています。

<div class="main">
  <div class="container">
    <h1>画像認識アプリ</h1>
    <input type="button" id="capture-button" value="Capture">
  </div>
  <div class="res-container">
    <div id="result"></div>
    <video id="video" controls autoplay></video>
    <canvas id="canvas" width="224" height="224" style="display:none"></canvas>
  </div>
</div>

このアプリは次のように動作します。

  1. アプリのスタート時、まずnavigator.mediaDevices.getUserMedia()を使って、ユーザーにカメラの使用許可を求めます。
  2. 許可が出たら、カメラの映像を<video>要素に割り当てます。これにより、カメラで撮っている映像が画面に表示されるようになります。
  3. 準備ができたので、モデルを読み込みます。
  4. [Caputure]ボタンがクリックされたら、<video>要素の動画をキャンバスのコンテキストで描画し、そこからイメージデータを得ます。
  5. イメージデータをmodel.classify()に渡します。モデルが分類を開始し、結果が配列で返ってきます。
  6. 結果の英語をGoogle Apps Scriptに渡して日本語に翻訳し、結果を表示します。

Google Apps Scriptでは次のプロジェクトを作成し、[ウェブアプリケーションとして導入]して公開しておきます。

以下はJavaScriptコードです。

// 必要な要素の取得
const canvas = document.getElementById('canvas');
const context = canvas.getContext('2d');
const captureButton = document.getElementById('capture-button');
const resultDiv = document.getElementById('result');

let model;

const setListener = () => {
    // [Capture]ボタンがクリックされたら、
    captureButton.addEventListener('click', function() {
        // <video>要素の動画をキャンバスのコンテキストで描画する
        context.drawImage(video, 0, 0, canvas.width, canvas.height);
        // そのイメージデータを得る
        const imageData = context.getImageData(0, 0, canvas.width, canvas.height);

        // MobileNetのモデルを使って、イメージデータを分類し、予測を得る
        model.classify(imageData).then(predictions => {
            // 結果表示に使用する要素を作成
            const containerDiv = document.createElement('div');
            const predictionsUl = document.createElement('ul');
            // 推測結果の配列を処理する。
            for (let i = 0; i < predictions.length; i++) {
                const li = document.createElement('li');
                li.style.fontSize = '20px';
                // predictions[i].classNameは分類名
                // predictions[i].probabilityはそうである確率

                const eText = predictions[i].probability.toFixed(3) + ': ' + predictions[i].className;
                // 英語から日本語への翻訳 Google Apps Scriptを使用
                const url = 'https://script.google.com/macros/s/AKfycbyG49Xo9-47h973XSXXDhFYwsX_ZKFM1cT9jwu2x8tdYiuLvfo/exec?text=' + eText;
                let jText = '';
                // 英単語をGoogle Apps Scriptに送り、結果の日本語単語を受け取る
                fetch(url).then((response) => {
                    return response.text();
                }).then((text) => {
                    const textNode = document.createTextNode(text);
                    // 結果をページに表示する
                    li.appendChild(textNode);
                    predictionsUl.appendChild(li);
                });
            }
            containerDiv.appendChild(predictionsUl);
            // 新しい<div>を、前の子の前に挿入する
            while (resultDiv.firstChild) {
                resultDiv.removeChild(resultDiv.firstChild);
            }
            resultDiv.appendChild(containerDiv);
        });
    }, false);
};

const start = () => {
    // カメラの使用が許可されたら、
    // スマホなどのリアカメラ用
    navigator.mediaDevices.getUserMedia({
        video: {
            facingMode: {
                exact: "environment"
            }
        }
    })

    // PCのカメラ用
    //navigator.mediaDevices.getUserMedia({video: true})
    .then(async(stream) => {
        // 動画のストリームを<video>要素に割り当てる。
        video.srcObject = stream;
        // MobileNetのモデルを読み込む。
        model = await mobilenet.load();;
        setListener();
    });
}
start();

TensorFlow.jsのコードを一切使う必要がないので、通常のWebアプリのように記述できます。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA