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