人工知能画像分類アプリ2

人工知能の機械学習モデルを使って画像を精度良く分類するアプリを作りましょう

このアプリは人工知能画像分類アプリとは異なりエクステンションを使わないので機械学習モデルの変更が簡単です

クリックしてアプリが動いているところを見てください

[プロジェクト]メニューから[プロジェクトを新規作成]を選択し、"WhatisThis2″と名前を付けます。

なぜエクテンションを追加しなくていいのか?

tensorflow.jsを使うとブラウザで機械学習モデルを利用することができます。MITで開発されたエクステンションLookExtensionはtensorflow.jを利用していますが、機械学習モデルを変更するためにはにエクステンションをビルドし直さなければならないので、簡単にはモデルを変更できません。その上、このエクステンションで使っているモデルはサイズが小さいので精度がそれほど良くないため、本格的なアプリの開発にLookExtensionを使えません。日本語化プロジェクトではこの問題を解決するために、ブラウザで使用するJavaScriptを含んだウェブページを使用するだけで機械学習モデルを使った画像分類方法を開発しました。この方法ではイメージファイルをウェブページで読み込むために外部ウェブサイトを利用していますが、ウェブページ内のJavaScriptを変更するだけでモデルを容易に変更できます。

デザイン編集

レイアウトとコンポーネントの配置

下図のようにユーザーインターフェースパレットからウェブビュー、テキストボックス、レイアウトパレットから横並びレイアウトを配置し、横並びレイアウトの中にユーザーインターフェースパレットから二つのボタンをドラッグアンドドロップし撮影ボタン、推論ボタンと名前を変更して配置します。見えないコンポーネントとしてメディアパレットからカメラ、タイマーを、接続パレットから二つのWebをドラッグアンドドロップしアップロード、ファイル削除と名前を変更します。テキストボックス1のヒントは「推論結果」に、撮影ボタンのテキストは「イメージ撮影」、推論ボタンのテキストは「推論」にします。

クリックして拡大

JavaScriptを含んだウェブページの追加

以下のhtmlファイルを作成し、メディアの"ファイルをアップロード"ボタンをクリックしてアセットに追加します。ファイル名はindex.htmlにしてください。以下はこのファイルの簡単な説明です。

行3:tensowflow.jsの読み込み
行4:MobileNetの読み込み
行10:撮影したイメージファイルの表示タグ
行18-24:WebGL2判別関数
行27-30:イメージ差し替え関数setimage()。App Inventorアプリから渡されるイメージファイルのURLをイメージタグにセットします
行33-44:推論関数classify()。推論を行い結果をApp Inventorアプリに渡します
行47-62:初期化関数app()。WebGL2の有無を判別してbackEndを設定したあと、MobileNetモデルを読み込みます

<html>
<head>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs"></script>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/mobilenet"></script>
</head>
<body>
<div><input type="text" id="output" size="100" value=""></div>


<img id="img" crossorigin src="https://img.appinventor.tmsoftwareinc.com/images/tfjs.png" width="80%"/>



<script >
let net;


var supportsWebGL2 = ( function () {
try {
return !! window.WebGLRenderingContext && !! document.createElement( 'canvas' ).getContext( 'webgl2' );
} catch( e ) {
return false;
}
} )();


function setimage() {
var appInventorInput = window.AppInventor.getWebViewString();
document.getElementById('img').src = appInventorInput;
}


async function classify() {
window.AppInventor.setWebViewString('');


const imgEl = document.getElementById('img');


const result = await net.classify(imgEl);
const ret = result[0]['className'];
// document.getElementById("output").value = ret;
window.AppInventor.setWebViewString(ret);
}


async function app() {
if(supportsWebGL2){
document.getElementById("output").value = 'WebGL2 is supported';
}else{
document.getElementById("output").value = 'WebGL2 is not supported';
tf.setBackend('cpu');
}


document.getElementById("output").value = 'モデル読み込み中..';


// Read MobileNet
net = await mobilenet.load();
document.getElementById("output").value = 'モデル読み込み完了';
}


app();
</script>
</body>
</html>

ブロック編集機能を使用したプログラミング

アプリの動作をプログラミングするには、 ブロック編集機能にアクセスする必要があります。 画面右上のブロック編集ボタンをクリックしてブロック編集機能に行きます。

グローバル変数

はじめにグローバル変数を定義します。組み込みブロック内の変数をクリックして”グローバル変数 変数名 を次の値で初期化”ブロックをドラッグアンドドロップして下図のように設定してください。productionはapkファイルをビルドする時は”真”、MIT AI2 Companionで実行する時は”偽”にします。imageHostはイメージファイルをアップロードするウェブサーバーです。タイマー待ち時間は推論結果を取得するまでの待ち時間をミリ秒で指定します。その他は一時的に使う変数です。

クリックして拡大

スクリーン初期化イベント

“いつもScreen1初期化したら“ブロックに以下のブロックを組み込みます。最初の三つは一時グローバル変数を設定しています。順にアップロードしたイメージファイルのURL、イメージファイルのアップロードに使うスクリプトのURL、イメージファイルの削除に使うスクリプトのURLです。次のもしブロックはapkファイルをビルドする時とMIT AI2 Companionで実行する時はアセットのパスが異なるためにウェブビューのURLに異なるパスを設定しています。最後にタイマーの待ち時間を設定し、タイマーを無効にします。

クリックして拡大

撮影ボタンクリックイベント

“撮影ボタンをクリックされたら“ブロックに“テキストボックス1テキスト“ブロックに空白テキストを組み込み、“呼び出すカメラ1撮影する“ブロックと、“推論ボタン有効を“ブロックにロジックの偽ブロックを組み込んだものを組み込みます。

撮影終了後イベント

“いつもカメラ1撮影終了後“ブロックでグローバル変数のphotoPathに撮影したイメージを設定し、アップロードWebのURLにグローバル変数のuploadURLを設定してアップロードWebにイメージをPostしてアップロードします。同時に推論ボタンを有効にします。

アップロード結果取得イベント

“いつもアップロードテキストに受け取ったら“ブロックで、アップロードが成功するとアップロードしたファイル名がレスポンスコンテントに返ってくるのでグローバル変数のimageNameにこのファイル名を設定し、ウェブビュー1のWebView文字列にイメージファイルのフルURLをセットして、setimage()関数を呼び出します。これによりアップロードしたイメージがスクリーンに表示されます。

推論ボタンクリックイベント

“推論ボタンをクリックされたら“ブロックに、“テキストボックス1テキスト“ブロックに空白テキストを組み込み、classify()関数を呼び出し推論を実行します。同時にタイマーを有効にします。

タイマーイベント

classify()関数を呼び出してからウェブビュー1のWebView文字列が返ってくるのには時間がかかるので、タイマーを使ってしばらく待っています。この時間はグローバル変数のタイマー待ち時間で設定していますが、500ミリ秒(0.5秒)です。“いつもタイマー1タイマー“ブロックで、まずタイマー1を無効にして、テキストボックス1テキストにウェブビュー1のWebView文字列を表示し、ファイル削除WebのURLにグローバル変数のremoveURLにファイル名を結合したURLを設定してからファイル削除Webをメソッドで呼び出してファイルを削除します。

これで完成です。スマホでテストしてください。分類結果は英語で下部に表示されます。

 

クリックして拡大

ソースコードのダウンロード

App Inventorでこのサンプルを使用したい場合は、 ソースコードをコンピュータにダウンロードしてからApp Inventorを開き、[ プロジェクト ]をクリックして[ローカルコンピュータからプロジェクト(.aia)をインポート]を選択し、ソースコードを選択してインポートしてください。

PHPソースコード

イメージファイルのアップロードと削除に使っているPHPソースコードです。ご自分のウェブサーバーを使うときに参考にしてください。ブラウザのセキュリティーのためにウェブサーバーはHeaderにAccess-Control-Allow-Origin “*" を返す必要があります。Apacheウェブサーバーの場合は Header set Access-Control-Allow-Origin “*" を設定します。

upload.php

<?php
$data = file_get_contents('php://input');
$tmpfname = tempnam("/var/www/------/images", "prefix");
if (!(file_put_contents($tmpfname,$data) === FALSE)) echo basename($tmpfname); // file could be empty
else echo "File xfer failed.";
?>

remove.php

<?php
if(isset($_GET['fn'])) {
    $fname = "/var/www/------/images/" . $_GET['fn'];;
    if(file_exists($fname)) {
        echo "unlinked $fname";
        unlink($fname);
    }
}
?>

チュートリアル